From 884d3ea4d8662b7ba3a17f75906d217d457aba08 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 06:19:05 -0400 Subject: [PATCH 0001/1537] Rip out OIS, fill the holes with SDL goodness. WIP. --- CMakeLists.txt | 8 +- apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 155 ++++++----- apps/openmw/mwinput/inputmanagerimp.hpp | 36 ++- apps/openmw/mwinput/sdlinputwrapper.cpp | 70 +++++ apps/openmw/mwinput/sdlinputwrapper.hpp | 35 +++ cmake/FindSDL2.cmake | 180 +++++++++++++ extern/oics/CMakeLists.txt | 1 + extern/oics/ICSInputControlSystem.cpp | 241 +++++++++--------- extern/oics/ICSInputControlSystem.h | 54 ++-- .../oics/ICSInputControlSystem_joystick.cpp | 113 ++++---- .../oics/ICSInputControlSystem_keyboard.cpp | 26 +- extern/oics/ICSInputControlSystem_mouse.cpp | 32 +-- extern/oics/ICSPrerequisites.h | 14 +- extern/oics/OISCompat.h | 90 +++++++ 15 files changed, 722 insertions(+), 336 deletions(-) create mode 100644 apps/openmw/mwinput/sdlinputwrapper.cpp create mode 100644 apps/openmw/mwinput/sdlinputwrapper.hpp create mode 100644 cmake/FindSDL2.cmake create mode 100644 extern/oics/OISCompat.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 766167672e..b1eb91d766 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,7 +204,7 @@ endif() find_package(OGRE REQUIRED) find_package(MyGUI REQUIRED) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) -find_package(OIS REQUIRED) +find_package(SDL2 REQUIRED) find_package(OpenAL REQUIRED) find_package(Bullet REQUIRED) IF(OGRE_STATIC) @@ -218,7 +218,8 @@ ENDIF(OGRE_STATIC) include_directories("." ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_Terrain_INCLUDE_DIR} - ${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} + ${SDL2_INCLUDE_DIR} + ${Boost_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR} ${MYGUI_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS} @@ -227,7 +228,7 @@ include_directories("." ${LIBDIR} ) -link_directories(${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) +link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) if (APPLE) # List used Ogre plugins @@ -361,6 +362,7 @@ if(DPKG_PROGRAM) SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW esmtool;Esmtool omwlauncher;OMWLauncher mwiniimporter;MWiniImporter") + #TODO: should SDL2 be mentioned in here somewhere? SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.3.0 (>= 1.3.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2), libqtgui4 (>= 4.7.0)") SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 56147b5008..88a05c8104 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ add_openmw_dir (mwrender ) add_openmw_dir (mwinput - inputmanagerimp + inputmanagerimp sdlinputwrapper ) add_openmw_dir (mwgui @@ -103,6 +103,7 @@ target_link_libraries(openmw ${SOUND_INPUT_LIBRARY} ${BULLET_LIBRARIES} ${MYGUI_LIBRARIES} + ${SDL2_LIBRARY} ${MYGUI_PLATFORM_LIBRARIES} "shiny" "shiny.OgrePlatform" diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 995da8f34b..a6f0f64d46 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,8 +9,6 @@ #include -#include - #include #include #include @@ -25,6 +23,8 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" +using namespace ICS; + namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, @@ -59,14 +59,19 @@ namespace MWInput window->getCustomAttribute("WINDOW", &windowHnd); + + // Set non-exclusive mouse and keyboard input if the user requested + // it. + + //TODO: re-enable this and make it work with SDL + /* + std::ostringstream windowHndStr; OIS::ParamList pl; windowHndStr << windowHnd; pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); - // Set non-exclusive mouse and keyboard input if the user requested - // it. if (debug) { #if defined OIS_WIN32_PLATFORM @@ -89,6 +94,7 @@ namespace MWInput std::string("true"))); #endif } + */ #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events @@ -97,24 +103,17 @@ namespace MWInput SetFrontProcess(&psn); #endif - mInputManager = OIS::InputManager::createInputSystem( pl ); - - // Create all devices - mKeyboard = static_cast(mInputManager->createInputObject - ( OIS::OISKeyboard, true )); - mMouse = static_cast(mInputManager->createInputObject - ( OIS::OISMouse, true )); - - mKeyboard->setEventCallback (this); - mMouse->setEventCallback (this); - - adjustMouseRegion (window->getWidth(), window->getHeight()); - - MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, mMouse->getMouseState ().Z.abs); + mInputManager = new MWSDLInputWrapper(window); + mInputManager->setMouseEventCallback (this); + mInputManager->setKeyboardEventCallback (this); std::string file = userFileExists ? userFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); + adjustMouseRegion (window->getWidth(), window->getHeight()); + + MyGUI::InputManager::getInstance().injectMouseMove(mMouseX, mMouseY, 0); + loadKeyDefaults(); for (int i = 0; i < A_Last; ++i) @@ -139,9 +138,7 @@ namespace MWInput delete mInputCtrl; - mInputManager->destroyInputObject(mKeyboard); - mInputManager->destroyInputObject(mMouse); - OIS::InputManager::destroyInputSystem(mInputManager); + delete mInputManager; } void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) @@ -240,8 +237,7 @@ namespace MWInput void InputManager::update(float dt, bool loading) { // Tell OIS to handle all input events - mKeyboard->capture(); - mMouse->capture(); + mInputManager->capture(); // inject some fake mouse movement to force updating MyGUI's widget states // this shouldn't do any harm since we're moving back to the original position afterwards @@ -304,7 +300,7 @@ namespace MWInput if (mControlSwitch["playerviewswitch"]) { // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mKeyboard->isModifierDown (OIS::Keyboard::Alt)) { + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(KMOD_ALT)) { if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) { @@ -419,37 +415,38 @@ namespace MWInput void InputManager::adjustMouseRegion(int width, int height) { - const OIS::MouseState &ms = mMouse->getMouseState(); - ms.width = width; - ms.height = height; + mInputCtrl->adjustMouseRegion(width, height); } - bool InputManager::keyPressed( const OIS::KeyEvent &arg ) + bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { mInputCtrl->keyPressed (arg); - unsigned int text = arg.text; + unsigned int text = arg.keysym.unicode; + + //TODO: Check if we need this with SDL + /* #ifdef __APPLE__ // filter \016 symbol for F-keys on OS X - if ((arg.key >= OIS::KC_F1 && arg.key <= OIS::KC_F10) || - (arg.key >= OIS::KC_F11 && arg.key <= OIS::KC_F15)) { + if ((arg.key >= SDLK_F1 && arg.key <= SDLK_F10) || + (arg.key >= SDLK_F11 && arg.key <= SDLK_F15)) { text = 0; } #endif - - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.key), text); + */ + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.keysym.sym), text); return true; } - bool InputManager::keyReleased( const OIS::KeyEvent &arg ) + bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { mInputCtrl->keyReleased (arg); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.key)); + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.keysym.sym)); return true; } - bool InputManager::mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) + bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { mInputCtrl->mousePressed (arg, id); @@ -467,7 +464,7 @@ namespace MWInput return true; } - bool InputManager::mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ) + bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) { mInputCtrl->mouseReleased (arg, id); @@ -476,7 +473,7 @@ namespace MWInput return true; } - bool InputManager::mouseMoved( const OIS::MouseEvent &arg ) + bool InputManager::mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ) { mInputCtrl->mouseMoved (arg); @@ -488,11 +485,13 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX += float(arg.state.X.rel) * mUISensitivity; - mMouseY += float(arg.state.Y.rel) * mUISensitivity * mUIYMultiplier; + mMouseX += float(arg.xrel) * mUISensitivity; + mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); - mMouseWheel = arg.state.Z.abs; + + //there's no such thing as an absolute z position, so let's keep track of it ourselves + mMouseWheel += arg.zrel; MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } @@ -501,8 +500,8 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.xrel * mCameraSensitivity * 0.2; + float y = arg.yrel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier; MWBase::World *world = MWBase::Environment::get().getWorld(); world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); @@ -679,38 +678,38 @@ namespace MWInput // across different versions of OpenMW (in the case where another input action is added) std::map defaultKeyBindings; - defaultKeyBindings[A_Activate] = OIS::KC_SPACE; - defaultKeyBindings[A_MoveBackward] = OIS::KC_S; - defaultKeyBindings[A_MoveForward] = OIS::KC_W; - defaultKeyBindings[A_MoveLeft] = OIS::KC_A; - defaultKeyBindings[A_MoveRight] = OIS::KC_D; - defaultKeyBindings[A_ToggleWeapon] = OIS::KC_F; - defaultKeyBindings[A_ToggleSpell] = OIS::KC_R; - defaultKeyBindings[A_QuickKeysMenu] = OIS::KC_F1; - defaultKeyBindings[A_Console] = OIS::KC_F2; - defaultKeyBindings[A_Crouch] = OIS::KC_LCONTROL; - defaultKeyBindings[A_AutoMove] = OIS::KC_Q; - defaultKeyBindings[A_Jump] = OIS::KC_E; - defaultKeyBindings[A_Journal] = OIS::KC_J; - defaultKeyBindings[A_Rest] = OIS::KC_T; - defaultKeyBindings[A_GameMenu] = OIS::KC_ESCAPE; - defaultKeyBindings[A_TogglePOV] = OIS::KC_TAB; - defaultKeyBindings[A_QuickKey1] = OIS::KC_1; - defaultKeyBindings[A_QuickKey2] = OIS::KC_2; - defaultKeyBindings[A_QuickKey3] = OIS::KC_3; - defaultKeyBindings[A_QuickKey4] = OIS::KC_4; - defaultKeyBindings[A_QuickKey5] = OIS::KC_5; - defaultKeyBindings[A_QuickKey6] = OIS::KC_6; - defaultKeyBindings[A_QuickKey7] = OIS::KC_7; - defaultKeyBindings[A_QuickKey8] = OIS::KC_8; - defaultKeyBindings[A_QuickKey9] = OIS::KC_9; - defaultKeyBindings[A_QuickKey10] = OIS::KC_0; - defaultKeyBindings[A_Screenshot] = OIS::KC_SYSRQ; - defaultKeyBindings[A_ToggleHUD] = OIS::KC_F12; + defaultKeyBindings[A_Activate] = SDLK_SPACE; + defaultKeyBindings[A_MoveBackward] = SDLK_s; + defaultKeyBindings[A_MoveForward] = SDLK_w; + defaultKeyBindings[A_MoveLeft] = SDLK_a; + defaultKeyBindings[A_MoveRight] = SDLK_d; + defaultKeyBindings[A_ToggleWeapon] = SDLK_f; + defaultKeyBindings[A_ToggleSpell] = SDLK_r; + defaultKeyBindings[A_QuickKeysMenu] = SDLK_F1; + defaultKeyBindings[A_Console] = SDLK_F2; + defaultKeyBindings[A_Crouch] = SDLK_LCTRL; + defaultKeyBindings[A_AutoMove] = SDLK_q; + defaultKeyBindings[A_Jump] = SDLK_e; + defaultKeyBindings[A_Journal] = SDLK_j; + defaultKeyBindings[A_Rest] = SDLK_t; + defaultKeyBindings[A_GameMenu] = SDLK_ESCAPE; + defaultKeyBindings[A_TogglePOV] = SDLK_TAB; + defaultKeyBindings[A_QuickKey1] = SDLK_1; + defaultKeyBindings[A_QuickKey2] = SDLK_2; + defaultKeyBindings[A_QuickKey3] = SDLK_3; + defaultKeyBindings[A_QuickKey4] = SDLK_4; + defaultKeyBindings[A_QuickKey5] = SDLK_5; + defaultKeyBindings[A_QuickKey6] = SDLK_6; + defaultKeyBindings[A_QuickKey7] = SDLK_7; + defaultKeyBindings[A_QuickKey8] = SDLK_8; + defaultKeyBindings[A_QuickKey9] = SDLK_9; + defaultKeyBindings[A_QuickKey10] = SDLK_0; + defaultKeyBindings[A_Screenshot] = SDLK_SYSREQ; + defaultKeyBindings[A_ToggleHUD] = SDLK_F12; std::map defaultMouseButtonBindings; - defaultMouseButtonBindings[A_Inventory] = OIS::MB_Right; - defaultMouseButtonBindings[A_Use] = OIS::MB_Left; + defaultMouseButtonBindings[A_Inventory] = SDL_BUTTON_RIGHT; + defaultMouseButtonBindings[A_Use] = SDL_BUTTON_LEFT; for (int i = 0; i < A_Last; ++i) { @@ -728,14 +727,14 @@ namespace MWInput } if (!controlExists || force || - ( mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) == OIS::KC_UNASSIGNED + ( mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) == SDLK_UNKNOWN && mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { clearAllBindings (control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end()) - mInputCtrl->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); + mInputCtrl->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()) mInputCtrl->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } @@ -786,7 +785,7 @@ namespace MWInput ICS::Control* c = mInputCtrl->getChannel (action)->getAttachedControls ().front().control; - if (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE) != OIS::KC_UNASSIGNED) + if (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE) != SDLK_UNKNOWN) return mInputCtrl->keyCodeToString (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE)); else if (mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) return "#{sMouse} " + boost::lexical_cast(mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE)); @@ -842,7 +841,7 @@ namespace MWInput } void InputManager::keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , OIS::KeyCode key, ICS::Control::ControlChangingDirection direction) + , SDL_Keycode key, ICS::Control::ControlChangingDirection direction) { clearAllBindings(control); ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction); @@ -892,7 +891,7 @@ namespace MWInput void InputManager::clearAllBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first - if (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) != OIS::KC_UNASSIGNED) + if (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) != SDLK_UNKNOWN) mInputCtrl->removeKeyBinding (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE)); if (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) mInputCtrl->removeMouseButtonBinding (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE)); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9deed1f285..3677f9070a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -6,6 +6,7 @@ #include #include "../mwbase/inputmanager.hpp" +#include "sdlinputwrapper.hpp" namespace OEngine { @@ -35,18 +36,9 @@ namespace ICS class InputControlSystem; } -namespace OIS -{ - class Keyboard; - class Mouse; - class InputManager; -} - -#include -#include - #include #include +#include namespace MWInput { @@ -54,7 +46,12 @@ namespace MWInput /** * @brief Class that handles all input and key bindings for OpenMW. */ - class InputManager : public MWBase::InputManager, public OIS::KeyListener, public OIS::MouseListener, public ICS::ChannelListener, public ICS::DetectingBindingListener + class InputManager : + public MWBase::InputManager, + public ICS::MWSDLKeyListener, + public ICS::MWSDLMouseListener, + public ICS::ChannelListener, + public ICS::DetectingBindingListener { public: InputManager(OEngine::Render::OgreRenderer &_ogre, @@ -85,12 +82,12 @@ namespace MWInput virtual void resetToDefaultBindings(); public: - virtual bool keyPressed( const OIS::KeyEvent &arg ); - virtual bool keyReleased( const OIS::KeyEvent &arg ); + virtual bool keyPressed(const SDL_KeyboardEvent &arg ); + virtual bool keyReleased( const SDL_KeyboardEvent &arg ); - virtual bool mousePressed( const OIS::MouseEvent &arg, OIS::MouseButtonID id ); - virtual bool mouseReleased( const OIS::MouseEvent &arg, OIS::MouseButtonID id ); - virtual bool mouseMoved( const OIS::MouseEvent &arg ); + virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); + virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); + virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); @@ -98,7 +95,7 @@ namespace MWInput , ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction); virtual void keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control - , OIS::KeyCode key, ICS::Control::ControlChangingDirection direction); + , SDL_Keycode key, ICS::Control::ControlChangingDirection direction); virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control , unsigned int button, ICS::Control::ControlChangingDirection direction); @@ -125,9 +122,8 @@ namespace MWInput ICS::InputControlSystem* mInputCtrl; - OIS::Keyboard* mKeyboard; - OIS::Mouse* mMouse; - OIS::InputManager* mInputManager; + + MWSDLInputWrapper* mInputManager; std::string mUserFile; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp new file mode 100644 index 0000000000..60c7e8f7a3 --- /dev/null +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -0,0 +1,70 @@ +#include "sdlinputwrapper.hpp" +#include + +namespace MWInput +{ + MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : + mWindow(window), mStarted(false), mSDLWindow(NULL) + { + _start(); + } + + MWSDLInputWrapper::~MWSDLInputWrapper() + { + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + SDL_Quit(); + } + + void MWSDLInputWrapper::capture() + { + _start(); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + mKeyboardListener->keyPressed(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + } + } + } + + bool MWSDLInputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void MWSDLInputWrapper::_start() + { + Uint32 flags = SDL_INIT_VIDEO; + if(SDL_WasInit(flags) == 0) + { + //get the HWND from ogre's renderwindow + size_t windowHnd; + mWindow->getCustomAttribute("WINDOW", &windowHnd); + + //just use that one for input + SDL_Init(flags); + mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + } + } +} diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp new file mode 100644 index 0000000000..ee07efbdb4 --- /dev/null +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -0,0 +1,35 @@ +#ifndef _MWINPUT_SDLINPUTWRAPPER_H +#define _MWINPUT_SDLINPUTWRAPPER_H + +#include "SDL2/SDL_events.h" +#include +#include + + +namespace MWInput +{ + class MWSDLInputWrapper + { + public: + MWSDLInputWrapper(Ogre::RenderWindow* window); + ~MWSDLInputWrapper(); + + void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } + void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } + + void capture(); + bool isModifierHeld(int mod); + + private: + ICS::MWSDLMouseListener* mMouseListener; + ICS::MWSDLKeyListener* mKeyboardListener; + Ogre::RenderWindow* mWindow; + SDL_Window* mSDLWindow; + + bool mStarted; + void _start(); + + }; +} + +#endif diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake new file mode 100644 index 0000000000..614426cccf --- /dev/null +++ b/cmake/FindSDL2.cmake @@ -0,0 +1,180 @@ +# Locate SDL2 library +# This module defines +# SDL2_LIBRARY, the name of the library to link against +# SDL2_FOUND, if false, do not try to link to SDL2 +# SDL2_INCLUDE_DIR, where to find SDL.h +# +# This module responds to the the flag: +# SDL2_BUILDING_LIBRARY +# If this is defined, then no SDL2_main will be linked in because +# only applications need main(). +# Otherwise, it is assumed you are building an application and this +# module will attempt to locate and set the the proper link flags +# as part of the returned SDL2_LIBRARY variable. +# +# Don't forget to include SDL2main.h and SDL2main.m your project for the +# OS X framework based version. (Other versions link to -lSDL2main which +# this module will try to find on your behalf.) Also for OS X, this +# module will automatically add the -framework Cocoa on your behalf. +# +# +# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration +# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library +# (SDL2.dll, libsdl2.so, SDL2.framework, etc). +# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again. +# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value +# as appropriate. These values are used to generate the final SDL2_LIBRARY +# variable, but when these values are unset, SDL2_LIBRARY does not get created. +# +# +# $SDL2DIR is an environment variable that would +# correspond to the ./configure --prefix=$SDL2DIR +# used in building SDL2. +# l.e.galup 9-20-02 +# +# Modified by Eric Wing. +# Added code to assist with automated building by using environmental variables +# and providing a more controlled/consistent search behavior. +# Added new modifications to recognize OS X frameworks and +# additional Unix paths (FreeBSD, etc). +# Also corrected the header search path to follow "proper" SDL2 guidelines. +# Added a search for SDL2main which is needed by some platforms. +# Added a search for threads which is needed by some platforms. +# Added needed compile switches for MinGW. +# +# On OSX, this will prefer the Framework version (if found) over others. +# People will have to manually change the cache values of +# SDL2_LIBRARY to override this selection or set the CMake environment +# CMAKE_INCLUDE_PATH to modify the search paths. +# +# Note that the header path has changed from SDL2/SDL.h to just SDL.h +# This needed to change because "proper" SDL2 convention +# is #include "SDL.h", not . This is done for portability +# reasons because not all systems place things in SDL2/ (see FreeBSD). +# +# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake +# module with the minor edit of changing "SDL" to "SDL2" where necessary. This +# was not created for redistribution, and exists temporarily pending official +# SDL2 CMake modules. + +#============================================================================= +# Copyright 2003-2009 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +FIND_PATH(SDL2_INCLUDE_DIR SDL.h + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES include/SDL2 include + PATHS + ~/Library/Frameworks + /Library/Frameworks + /usr/local/include/SDL2 + /usr/include/SDL2 + /sw # Fink + /opt/local # DarwinPorts + /opt/csw # Blastwave + /opt +) +#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}") + +FIND_LIBRARY(SDL2_LIBRARY_TEMP + NAMES SDL2 + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt +) + +#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}") + +IF(NOT SDL2_BUILDING_LIBRARY) + IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + FIND_LIBRARY(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + $ENV{SDL2DIR} + PATH_SUFFIXES lib64 lib + PATHS + /sw + /opt/local + /opt/csw + /opt + ) + ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework") +ENDIF(NOT SDL2_BUILDING_LIBRARY) + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +IF(NOT APPLE) + FIND_PACKAGE(Threads) +ENDIF(NOT APPLE) + +# MinGW needs an additional library, mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows +# (Actually on second look, I think it only needs one of the m* libraries.) +IF(MINGW) + SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW") +ENDIF(MINGW) + +SET(SDL2_FOUND "NO") +IF(SDL2_LIBRARY_TEMP) + # For SDL2main + IF(NOT SDL2_BUILDING_LIBRARY) + IF(SDL2MAIN_LIBRARY) + SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(SDL2MAIN_LIBRARY) + ENDIF(NOT SDL2_BUILDING_LIBRARY) + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + IF(APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa") + ENDIF(APPLE) + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + IF(NOT APPLE) + SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT}) + ENDIF(NOT APPLE) + + # For MinGW library + IF(MINGW) + SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) + ENDIF(MINGW) + + # Set the final string here so the GUI reflects the final state. + SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") + # Set the temp variable to INTERNAL so it is not seen in the CMake GUI + SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "") + + SET(SDL2_FOUND "YES") +ENDIF(SDL2_LIBRARY_TEMP) + +INCLUDE(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR) diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt index 7c14387a4b..2e2a7a6d6b 100644 --- a/extern/oics/CMakeLists.txt +++ b/extern/oics/CMakeLists.txt @@ -9,6 +9,7 @@ set(OICS_SOURCE_FILES ICSInputControlSystem_keyboard.cpp ICSInputControlSystem_mouse.cpp ICSInputControlSystem_joystick.cpp + OISCompat.h tinyxml.cpp tinyxmlparser.cpp tinyxmlerror.cpp diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 1702c853ed..159b3241ff 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -41,7 +41,7 @@ namespace ICS this->mActive = active; - this->fillOISKeysMap(); + this->fillSDLKeysMap(); ICS_LOG("Channel count = " + ToString(channelCount) ); for(size_t i=0;i::iterator it = mKeys.begin() + for(std::map::iterator it = mKeys.begin() ; it != mKeys.end() ; it++) { mKeyCodes[ it->second ] = it->first; } } - std::string InputControlSystem::keyCodeToString(OIS::KeyCode key) + std::string InputControlSystem::keyCodeToString(SDL_Keycode key) { return mKeyCodes[key]; } - OIS::KeyCode InputControlSystem::stringToKeyCode(std::string key) + SDL_Keycode InputControlSystem::stringToKeyCode(std::string key) { return mKeys[key]; } -} \ No newline at end of file + + void InputControlSystem::adjustMouseRegion(Uint16 width, Uint16 height) + { + mClientWidth = width; + mClientHeight = height; + } +} diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index f1c12d3b59..5d30b35cfb 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,6 +32,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" +#include "OISCompat.h" + #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 #define ICS_MOUSE_BINDING_MARGIN 30 @@ -48,9 +50,9 @@ namespace ICS }; class DllExport InputControlSystem : - public OIS::MouseListener, - public OIS::KeyListener, - public OIS::JoyStickListener + public MWSDLMouseListener, + public MWSDLKeyListener, + public MWSDLJoyStickListener { public: @@ -100,29 +102,30 @@ namespace ICS JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; // MouseListener - bool mouseMoved(const OIS::MouseEvent &evt); - bool mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID); - bool mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID); + bool mouseMoved(const MWSDLMouseMotionEvent &evt); + bool mousePressed(const SDL_MouseButtonEvent &evt, Uint8); + bool mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); // KeyListener - bool keyPressed(const OIS::KeyEvent &evt); - bool keyReleased(const OIS::KeyEvent &evt); + bool keyPressed(const SDL_KeyboardEvent &evt); + bool keyReleased(const SDL_KeyboardEvent &evt); // JoyStickListener - bool buttonPressed(const OIS::JoyStickEvent &evt, int button); - bool buttonReleased(const OIS::JoyStickEvent &evt, int button); - bool axisMoved(const OIS::JoyStickEvent &evt, int axis); - bool povMoved(const OIS::JoyStickEvent &evt, int index); - bool sliderMoved(const OIS::JoyStickEvent &evt, int index); + bool buttonPressed(const SDL_JoyButtonEvent &evt, int button); + bool buttonReleased(const SDL_JoyButtonEvent &evt, int button); + bool axisMoved(const SDL_JoyAxisEvent &evt, int axis); + bool povMoved(const SDL_JoyHatEvent &evt, int index); + //TODO: does this have an SDL equivalent? + //bool sliderMoved(const OIS::JoyStickEvent &evt, int index); - void addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction); + void addKeyBinding(Control* control, SDL_Keycode key, Control::ControlChangingDirection direction); void addMouseAxisBinding(Control* control, NamedAxis axis, Control::ControlChangingDirection direction); void addMouseButtonBinding(Control* control, unsigned int button, Control::ControlChangingDirection direction); void addJoystickAxisBinding(Control* control, int deviceId, int axis, Control::ControlChangingDirection direction); void addJoystickButtonBinding(Control* control, int deviceId, unsigned int button, Control::ControlChangingDirection direction); void addJoystickPOVBinding(Control* control, int deviceId, int index, POVAxis axis, Control::ControlChangingDirection direction); void addJoystickSliderBinding(Control* control, int deviceId, int index, Control::ControlChangingDirection direction); - void removeKeyBinding(OIS::KeyCode key); + void removeKeyBinding(SDL_Keycode key); void removeMouseAxisBinding(NamedAxis axis); void removeMouseButtonBinding(unsigned int button); void removeJoystickAxisBinding(int deviceId, int axis); @@ -130,7 +133,7 @@ namespace ICS void removeJoystickPOVBinding(int deviceId, int index, POVAxis axis); void removeJoystickSliderBinding(int deviceId, int index); - OIS::KeyCode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); + SDL_Keycode getKeyBinding(Control* control, ICS::Control::ControlChangingDirection direction); NamedAxis getMouseAxisBinding(Control* control, ICS::Control::ControlChangingDirection direction); unsigned int getMouseButtonBinding(Control* control, ICS::Control::ControlChangingDirection direction); int getJoystickAxisBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); @@ -138,14 +141,16 @@ namespace ICS POVBindingPair getJoystickPOVBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); int getJoystickSliderBinding(Control* control, int deviceId, ICS::Control::ControlChangingDirection direction); - std::string keyCodeToString(OIS::KeyCode key); - OIS::KeyCode stringToKeyCode(std::string key); + std::string keyCodeToString(SDL_Keycode key); + SDL_Keycode stringToKeyCode(std::string key); void enableDetectingBindingState(Control* control, Control::ControlChangingDirection direction); void cancelDetectingBindingState(); bool save(std::string fileName = ""); + void adjustMouseRegion (Uint16 width, Uint16 height); + protected: void loadKeyBinders(TiXmlElement* xmlControlNode); @@ -180,7 +185,7 @@ namespace ICS std::string mFileName; - typedef std::map ControlsKeyBinderMapType; // + typedef std::map ControlsKeyBinderMapType; // typedef std::map ControlsAxisBinderMapType; // typedef std::map ControlsButtonBinderMapType; // typedef std::map ControlsPOVBinderMapType; // @@ -202,8 +207,8 @@ namespace ICS std::vector mChannels; ControlsKeyBinderMapType mControlsKeyBinderMap; - std::map mKeys; - std::map mKeyCodes; + std::map mKeys; + std::map mKeyCodes; bool mActive; InputControlSystemLog* mLog; @@ -221,14 +226,17 @@ namespace ICS private: - void fillOISKeysMap(); + void fillSDLKeysMap(); + + Uint16 mClientWidth; + Uint16 mClientHeight; }; class DllExport DetectingBindingListener { public: virtual void keyBindingDetected(InputControlSystem* ICS, Control* control - , OIS::KeyCode key, Control::ControlChangingDirection direction); + , SDL_Keycode key, Control::ControlChangingDirection direction); virtual void mouseAxisBindingDetected(InputControlSystem* ICS, Control* control , InputControlSystem::NamedAxis axis, Control::ControlChangingDirection direction); diff --git a/extern/oics/ICSInputControlSystem_joystick.cpp b/extern/oics/ICSInputControlSystem_joystick.cpp index 1e66599ead..8e501d5018 100644 --- a/extern/oics/ICSInputControlSystem_joystick.cpp +++ b/extern/oics/ICSInputControlSystem_joystick.cpp @@ -26,6 +26,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSInputControlSystem.h" +#define SDL_JOY_AXIS_MIN -32768 +#define SDL_JOY_AXIS_MAX 32767 + namespace ICS { // load xml @@ -315,16 +318,16 @@ namespace ICS } // joyStick listeners - bool InputControlSystem::buttonPressed(const OIS::JoyStickEvent &evt, int button) + bool InputControlSystem::buttonPressed(const SDL_JoyButtonEvent &evt, int button) { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end()) + if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end()) + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); + if(it != mControlsJoystickButtonBinderMap[evt.which].end()) { it->second.control->setIgnoreAutoReverse(false); if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) @@ -348,21 +351,21 @@ namespace ICS else if(mDetectingBindingListener) { mDetectingBindingListener->joystickButtonBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), button, mDetectingBindingDirection); + mDetectingBindingControl, evt.which, button, mDetectingBindingDirection); } } return true; } - bool InputControlSystem::buttonReleased(const OIS::JoyStickEvent &evt, int button) + bool InputControlSystem::buttonReleased(const SDL_JoyButtonEvent &evt, int button) { if(mActive) { - if(mControlsJoystickButtonBinderMap.find(evt.device->getID()) != mControlsJoystickButtonBinderMap.end()) + if(mControlsJoystickButtonBinderMap.find(evt.which) != mControlsJoystickButtonBinderMap.end()) { - ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.device->getID()].find(button); - if(it != mControlsJoystickButtonBinderMap[evt.device->getID()].end()) + ControlsButtonBinderMapType::const_iterator it = mControlsJoystickButtonBinderMap[evt.which].find(button); + if(it != mControlsJoystickButtonBinderMap[evt.which].end()) { it->second.control->setChangingDirection(Control::STOP); } @@ -371,31 +374,29 @@ namespace ICS return true; } - bool InputControlSystem::axisMoved(const OIS::JoyStickEvent &evt, int axis) - { + bool InputControlSystem::axisMoved(const SDL_JoyAxisEvent &evt, int axis) + { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickAxisBinderMap.find(evt.device->getID()) != mControlsJoystickAxisBinderMap.end()) + if(mControlsJoystickAxisBinderMap.find(evt.which) != mControlsJoystickAxisBinderMap.end()) { - ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index + ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index Control* ctrl = joystickBinderItem.control; if(ctrl) { ctrl->setIgnoreAutoReverse(true); + + float axisRange = SDL_JOY_AXIS_MAX - SDL_JOY_AXIS_MAX; + float valDisplaced = (float)(evt.value - SDL_JOY_AXIS_MIN); + if(joystickBinderItem.direction == Control::INCREASE) { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)( evt.state.mAxes[axis].abs - OIS::JoyStick::MIN_AXIS); - ctrl->setValue( valDisplaced / axisRange ); } else if(joystickBinderItem.direction == Control::DECREASE) { - float axisRange = OIS::JoyStick::MAX_AXIS - OIS::JoyStick::MIN_AXIS; - float valDisplaced = (float)(evt.state.mAxes[axis].abs - OIS::JoyStick::MIN_AXIS); - ctrl->setValue( 1 - ( valDisplaced / axisRange ) ); } } @@ -403,15 +404,15 @@ namespace ICS } else if(mDetectingBindingListener) { - //ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.device->getID() ][ axis ]; // joystic axis start at 0 index + //ControlAxisBinderItem joystickBinderItem = mControlsJoystickAxisBinderMap[ evt.which ][ axis ]; // joystic axis start at 0 index //Control* ctrl = joystickBinderItem.control; //if(ctrl && ctrl->isAxisBindable()) if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) { - if( abs( evt.state.mAxes[axis].abs ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) + if( abs( evt.value ) > ICS_JOYSTICK_AXIS_BINDING_MARGIN) { mDetectingBindingListener->joystickAxisBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), axis, mDetectingBindingDirection); + mDetectingBindingControl, evt.which, axis, mDetectingBindingDirection); } } } @@ -420,20 +421,21 @@ namespace ICS return true; } - bool InputControlSystem::povMoved(const OIS::JoyStickEvent &evt, int index) - { + //Here be dragons, apparently + bool InputControlSystem::povMoved(const SDL_JoyHatEvent &evt, int index) + { if(mActive) { if(!mDetectingBindingControl) { - if(mControlsJoystickPOVBinderMap.find(evt.device->getID()) != mControlsJoystickPOVBinderMap.end()) + if(mControlsJoystickPOVBinderMap.find(evt.which) != mControlsJoystickPOVBinderMap.end()) { - std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.device->getID() ].find(index); - if(i != mControlsJoystickPOVBinderMap[ evt.device->getID() ].end()) + std::map::const_iterator i = mControlsJoystickPOVBinderMap[ evt.which ].find(index); + if(i != mControlsJoystickPOVBinderMap[ evt.which ].end()) { - if(evt.state.mPOV[index].direction != OIS::Pov::West - && evt.state.mPOV[index].direction != OIS::Pov::East - && evt.state.mPOV[index].direction != OIS::Pov::Centered) + if(evt.value != SDL_HAT_LEFT + && evt.value != SDL_HAT_RIGHT + && evt.value != SDL_HAT_CENTERED) { ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); if(it != i->second.end()) @@ -441,9 +443,9 @@ namespace ICS it->second.control->setIgnoreAutoReverse(false); if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) { - if(evt.state.mPOV[index].direction == OIS::Pov::North - || evt.state.mPOV[index].direction == OIS::Pov::NorthWest - || evt.state.mPOV[index].direction == OIS::Pov::NorthEast) + if(evt.value == SDL_HAT_UP + || evt.value == SDL_HAT_LEFTUP + || evt.value == SDL_HAT_RIGHTUP) { it->second.control->setChangingDirection(it->second.direction); } @@ -453,7 +455,7 @@ namespace ICS } } else - { + { if(it->second.control->getValue() == 1) { it->second.control->setChangingDirection(Control::DECREASE); @@ -466,9 +468,9 @@ namespace ICS } } - if(evt.state.mPOV[index].direction != OIS::Pov::North - && evt.state.mPOV[index].direction != OIS::Pov::South - && evt.state.mPOV[index].direction != OIS::Pov::Centered) + if(evt.value != SDL_HAT_UP + && evt.value != SDL_HAT_DOWN + && evt.value != SDL_HAT_CENTERED) { ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/EastWest ); if(it != i->second.end()) @@ -476,9 +478,9 @@ namespace ICS it->second.control->setIgnoreAutoReverse(false); if(!it->second.control->getAutoChangeDirectionOnLimitsAfterStop()) { - if(evt.state.mPOV[index].direction == OIS::Pov::East - || evt.state.mPOV[index].direction == OIS::Pov::NorthEast - || evt.state.mPOV[index].direction == OIS::Pov::SouthEast) + if(evt.value == SDL_HAT_RIGHT + || evt.value == SDL_HAT_RIGHTUP + || evt.value == SDL_HAT_RIGHTDOWN) { it->second.control->setChangingDirection(it->second.direction); } @@ -488,7 +490,7 @@ namespace ICS } } else - { + { if(it->second.control->getValue() == 1) { it->second.control->setChangingDirection(Control::DECREASE); @@ -501,7 +503,7 @@ namespace ICS } } - if(evt.state.mPOV[index].direction == OIS::Pov::Centered) + if(evt.value == SDL_HAT_CENTERED) { ControlsPOVBinderMapType::const_iterator it = i->second.find( /*POVAxis::*/NorthSouth ); if(it != i->second.end()) @@ -522,28 +524,30 @@ namespace ICS { if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) { - if(evt.state.mPOV[index].direction == OIS::Pov::West - || evt.state.mPOV[index].direction == OIS::Pov::East - || evt.state.mPOV[index].direction == OIS::Pov::North - || evt.state.mPOV[index].direction == OIS::Pov::South) + if(evt.value == SDL_HAT_LEFT + || evt.value == SDL_HAT_RIGHT + || evt.value == SDL_HAT_UP + || evt.value == SDL_HAT_DOWN) { POVAxis povAxis = NorthSouth; - if(evt.state.mPOV[index].direction == OIS::Pov::West - || evt.state.mPOV[index].direction == OIS::Pov::East) + if(evt.value == SDL_HAT_LEFT + || evt.value == SDL_HAT_RIGHT) { povAxis = EastWest; } mDetectingBindingListener->joystickPOVBindingDetected(this, - mDetectingBindingControl, evt.device->getID(), index, povAxis, mDetectingBindingDirection); + mDetectingBindingControl, evt.which, index, povAxis, mDetectingBindingDirection); } } } } - + return true; } + //TODO: does this have an SDL equivalent? + /* bool InputControlSystem::sliderMoved(const OIS::JoyStickEvent &evt, int index) { if(mActive) @@ -552,7 +556,7 @@ namespace ICS { if(mControlsJoystickSliderBinderMap.find(evt.device->getID()) != mControlsJoystickSliderBinderMap.end()) { - ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; + ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; Control* ctrl = joystickBinderItem.control; if(ctrl) { @@ -576,10 +580,6 @@ namespace ICS } else if(mDetectingBindingListener) { - /*ControlSliderBinderItem joystickBinderItem = mControlsJoystickSliderBinderMap[ evt.device->getID() ][ index ]; - Control* ctrl = joystickBinderItem.control; - if(ctrl && ctrl->isAxisBindable()) - {*/ if(mDetectingBindingControl && mDetectingBindingControl->isAxisBindable()) { if( abs( evt.state.mSliders[index].abX ) > ICS_JOYSTICK_SLIDER_BINDING_MARGIN) @@ -593,6 +593,7 @@ namespace ICS return true; } + */ // joystick auto bindings void DetectingBindingListener::joystickAxisBindingDetected(InputControlSystem* ICS, Control* control @@ -662,4 +663,4 @@ namespace ICS ICS->addJoystickSliderBinding(control, deviceId, slider, direction); ICS->cancelDetectingBindingState(); } -} \ No newline at end of file +} diff --git a/extern/oics/ICSInputControlSystem_keyboard.cpp b/extern/oics/ICSInputControlSystem_keyboard.cpp index 8ef81d9794..01d68f7843 100644 --- a/extern/oics/ICSInputControlSystem_keyboard.cpp +++ b/extern/oics/ICSInputControlSystem_keyboard.cpp @@ -49,7 +49,7 @@ namespace ICS } } - void InputControlSystem::addKeyBinding(Control* control, OIS::KeyCode key, Control::ControlChangingDirection direction) + void InputControlSystem::addKeyBinding(Control* control, SDL_Keycode key, Control::ControlChangingDirection direction) { ICS_LOG("\tAdding KeyBinder [key=" + keyCodeToString(key) + ", direction=" @@ -61,7 +61,7 @@ namespace ICS mControlsKeyBinderMap[ key ] = controlKeyBinderItem; } - void InputControlSystem::removeKeyBinding(OIS::KeyCode key) + void InputControlSystem::removeKeyBinding(SDL_Keycode key) { ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.find(key); if(it != mControlsKeyBinderMap.end()) @@ -70,7 +70,7 @@ namespace ICS } } - OIS::KeyCode InputControlSystem::getKeyBinding(Control* control + SDL_Keycode InputControlSystem::getKeyBinding(Control* control , ICS::Control::ControlChangingDirection direction) { ControlsKeyBinderMapType::iterator it = mControlsKeyBinderMap.begin(); @@ -83,15 +83,15 @@ namespace ICS it++; } - return OIS::KC_UNASSIGNED; + return SDLK_UNKNOWN; } - bool InputControlSystem::keyPressed(const OIS::KeyEvent &evt) + bool InputControlSystem::keyPressed(const SDL_KeyboardEvent &evt) { if(mActive) { if(!mDetectingBindingControl) { - ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key); + ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.keysym.sym); if(it != mControlsKeyBinderMap.end()) { it->second.control->setIgnoreAutoReverse(false); @@ -115,18 +115,18 @@ namespace ICS else if(mDetectingBindingListener) { mDetectingBindingListener->keyBindingDetected(this, - mDetectingBindingControl, evt.key, mDetectingBindingDirection); + mDetectingBindingControl, evt.keysym.sym, mDetectingBindingDirection); } } return true; } - bool InputControlSystem::keyReleased(const OIS::KeyEvent &evt) + bool InputControlSystem::keyReleased(const SDL_KeyboardEvent &evt) { if(mActive) { - ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.key); + ControlsKeyBinderMapType::const_iterator it = mControlsKeyBinderMap.find(evt.keysym.sym); if(it != mControlsKeyBinderMap.end()) { it->second.control->setChangingDirection(Control::STOP); @@ -137,14 +137,14 @@ namespace ICS } void DetectingBindingListener::keyBindingDetected(InputControlSystem* ICS, Control* control - , OIS::KeyCode key, Control::ControlChangingDirection direction) + , SDL_Keycode key, Control::ControlChangingDirection direction) { // if the key is used by another control, remove it ICS->removeKeyBinding(key); // if the control has a key assigned, remove it - OIS::KeyCode oldKey = ICS->getKeyBinding(control, direction); - if(oldKey != OIS::KC_UNASSIGNED) + SDL_Keycode oldKey = ICS->getKeyBinding(control, direction); + if(oldKey != SDLK_UNKNOWN) { ICS->removeKeyBinding(oldKey); } @@ -153,4 +153,4 @@ namespace ICS ICS->cancelDetectingBindingState(); } -} \ No newline at end of file +} diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index c62f1765e6..96197426a9 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -78,15 +78,15 @@ namespace ICS int button = 0; if(std::string(xmlMouseButtonBinder->Attribute("button")) == "LEFT") { - button = OIS::/*MouseButtonID::*/MB_Left; + button = SDL_BUTTON_LEFT; } else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "RIGHT") { - button = OIS::/*MouseButtonID::*/MB_Right; + button = SDL_BUTTON_RIGHT; } else if(std::string(xmlMouseButtonBinder->Attribute("button")) == "MIDDLE") { - button = OIS::/*MouseButtonID::*/MB_Middle; + button = SDL_BUTTON_MIDDLE; } else { @@ -219,39 +219,39 @@ namespace ICS } // mouse Listeners - bool InputControlSystem::mouseMoved(const OIS::MouseEvent &evt) + bool InputControlSystem::mouseMoved(const MWSDLMouseMotionEvent& evt) { if(mActive) { if(!mDetectingBindingControl) { - if(mXmouseAxisBinded && evt.state.X.rel) + if(mXmouseAxisBinded && evt.xrel) { ControlAxisBinderItem mouseBinderItem = mControlsMouseAxisBinderMap[ /*NamedAxis::*/X ]; Control* ctrl = mouseBinderItem.control; ctrl->setIgnoreAutoReverse(true); if(mouseBinderItem.direction == Control::INCREASE) { - ctrl->setValue( float( (evt.state.X.abs) / float(evt.state.width) ) ); + ctrl->setValue( float( (evt.x) / float(mClientWidth) ) ); } else if(mouseBinderItem.direction == Control::DECREASE) { - ctrl->setValue( 1 - float( evt.state.X.abs / float(evt.state.width) ) ); + ctrl->setValue( 1 - float( evt.x / float(mClientWidth) ) ); } } - if(mYmouseAxisBinded && evt.state.Y.rel) + if(mYmouseAxisBinded && evt.yrel) { ControlAxisBinderItem mouseBinderItem = mControlsMouseAxisBinderMap[ /*NamedAxis::*/Y ]; Control* ctrl = mouseBinderItem.control; ctrl->setIgnoreAutoReverse(true); if(mouseBinderItem.direction == Control::INCREASE) { - ctrl->setValue( float( (evt.state.Y.abs) / float(evt.state.height) ) ); + ctrl->setValue( float( (evt.y) / float(mClientHeight) ) ); } else if(mouseBinderItem.direction == Control::DECREASE) { - ctrl->setValue( 1 - float( evt.state.Y.abs / float(evt.state.height) ) ); + ctrl->setValue( 1 - float( evt.y / float(mClientHeight) ) ); } } @@ -282,9 +282,9 @@ namespace ICS mMouseAxisBindingInitialValues[2] = 0; } - mMouseAxisBindingInitialValues[0] += evt.state.X.rel; - mMouseAxisBindingInitialValues[1] += evt.state.Y.rel; - mMouseAxisBindingInitialValues[2] += evt.state.Z.rel; + mMouseAxisBindingInitialValues[0] += evt.xrel; + mMouseAxisBindingInitialValues[1] += evt.yrel; + mMouseAxisBindingInitialValues[2] += evt.zrel; if( abs(mMouseAxisBindingInitialValues[0]) > ICS_MOUSE_BINDING_MARGIN ) { @@ -308,7 +308,7 @@ namespace ICS return true; } - bool InputControlSystem::mousePressed(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) + bool InputControlSystem::mousePressed(const SDL_MouseButtonEvent &evt, Uint8 btn) { if(mActive) { @@ -345,7 +345,7 @@ namespace ICS return true; } - bool InputControlSystem::mouseReleased(const OIS::MouseEvent &evt, OIS::MouseButtonID btn) + bool InputControlSystem::mouseReleased(const SDL_MouseButtonEvent &evt, Uint8 btn) { if(mActive) { @@ -394,4 +394,4 @@ namespace ICS ICS->cancelDetectingBindingState(); } -} \ No newline at end of file +} diff --git a/extern/oics/ICSPrerequisites.h b/extern/oics/ICSPrerequisites.h index 3b5d1935b4..82c95c86ab 100644 --- a/extern/oics/ICSPrerequisites.h +++ b/extern/oics/ICSPrerequisites.h @@ -39,11 +39,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tinyxml.h" -#include -#include -#include -#include -#include +#include "SDL2/SDL_input.h" +#include "SDL2/SDL_keyboard.h" +#include "SDL2/SDL_mouse.h" +#include "SDL2/SDL_joystick.h" +#include "SDL2/SDL_events.h" /// Define the dll export qualifier if compiling for Windows @@ -65,8 +65,8 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /// Version defines #define ICS_VERSION_MAJOR 0 -#define ICS_VERSION_MINOR 3 -#define ICS_VERSION_PATCH 1 +#define ICS_VERSION_MINOR 4 +#define ICS_VERSION_PATCH 0 #define ICS_MAX_DEVICE_BUTTONS 30 diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h new file mode 100644 index 0000000000..18bdd6bae0 --- /dev/null +++ b/extern/oics/OISCompat.h @@ -0,0 +1,90 @@ +#ifndef _OIS_SDL_COMPAT_H +#define _OIS_SDL_COMPAT_H + +#include +#include + +//TODO: Remove this. Right now we want to remain as close to OIS as possible +//So we can easily test the SDL backend + +//////////// +// Events // +//////////// + +namespace ICS { + +/** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ +struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { + + Sint16 zrel; + + MWSDLMouseMotionEvent() + { + x = 0; + y = 0; + xrel = 0; + yrel = 0; + state = 0; + zrel = 0; + } + + MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) : + MWSDLMouseMotionEvent() + { + x = evt.x; + y = evt.y; + xrel = evt.xrel; + yrel = evt.yrel; + state = evt.state; + } + + MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) : + MWSDLMouseMotionEvent() + { + zrel = evt.y; + } +}; + + +/////////////// +// Listeners // +/////////////// + +class MWSDLMouseListener +{ +public: + virtual ~MWSDLMouseListener() {} + virtual bool mouseMoved( const MWSDLMouseMotionEvent &arg ) = 0; + virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; + virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; +}; + +class MWSDLKeyListener +{ +public: + virtual ~MWSDLKeyListener() {} + virtual bool keyPressed(const SDL_KeyboardEvent &arg) = 0; + virtual bool keyReleased(const SDL_KeyboardEvent &arg) = 0; +}; + +class MWSDLJoyStickListener +{ +public: + virtual ~MWSDLJoyStickListener() {} + /** @remarks Joystick button down event */ + virtual bool buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; + + /** @remarks Joystick button up event */ + virtual bool buttonReleased( const SDL_JoyButtonEvent &evt, int button ) = 0; + + /** @remarks Joystick axis moved event */ + virtual bool axisMoved( const SDL_JoyAxisEvent &arg, int axis ) = 0; + + //-- Not so common control events, so are not required --// + + //! Joystick Event, and povID + virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} +}; + +} +#endif From 3b1d285cf3898dfaee3336836e81403f379fde75 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 21:01:58 -0400 Subject: [PATCH 0002/1537] fix compile errors, work with unmodified SDL --- apps/openmw/mwinput/sdlinputwrapper.cpp | 50 ++++++++++++++++++++++++- extern/oics/OISCompat.h | 22 +++++++---- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 60c7e8f7a3..61fc3fc8b8 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -1,5 +1,15 @@ #include "sdlinputwrapper.hpp" #include +#include + +#include + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +# include +# include +# include +#endif + namespace MWInput { @@ -62,9 +72,45 @@ namespace MWInput size_t windowHnd; mWindow->getCustomAttribute("WINDOW", &windowHnd); - //just use that one for input - SDL_Init(flags); + //kindly ask SDL not to trash our OGL context + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + SDL_Init(SDL_INIT_VIDEO); + + //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + //linux-specific event-handling fixups + SDL_SysWMinfo wm_info; + SDL_VERSION(&wm_info.version); + + if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) + { + printf("SDL version %d.%d.%d\n", wm_info.version.major, wm_info.version.minor, wm_info.version.patch); + + Display* display = wm_info.info.x11.display; + Window w = wm_info.info.x11.window; + + // Set the input hints so we get keyboard input + XWMHints *wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + wmhints->flags = InputHint; + XSetWMHints(display, w, wmhints); + XFree(wmhints); + } + + //make sure to subscribe to XLib's events + XSelectInput(display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + XFlush(display); + } +#endif } } } diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index 18bdd6bae0..74b6acde10 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -20,17 +20,12 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { MWSDLMouseMotionEvent() { - x = 0; - y = 0; - xrel = 0; - yrel = 0; - state = 0; - zrel = 0; + _init(); } - MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) : - MWSDLMouseMotionEvent() + MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) { + _init(); x = evt.x; y = evt.y; xrel = evt.xrel; @@ -41,8 +36,19 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) : MWSDLMouseMotionEvent() { + _init(); zrel = evt.y; } + + void _init() + { + x = 0; + y = 0; + xrel = 0; + yrel = 0; + state = 0; + zrel = 0; + } }; From 00a2a5c358e8a4ee189f92f7b0423605b3a308a2 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 21:04:36 -0400 Subject: [PATCH 0003/1537] remove some more of my mess --- extern/oics/OISCompat.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index 74b6acde10..e8fd6904cb 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -33,8 +33,7 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { state = evt.state; } - MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) : - MWSDLMouseMotionEvent() + MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) { _init(); zrel = evt.y; From 6b49b8ab47e4dcbd363a3ae281b55026c2b5759a Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Tue, 8 Jan 2013 22:14:30 -0400 Subject: [PATCH 0004/1537] MyGUI doesn't care for SDL's mouse button ordering, send it what it expects --- apps/openmw/mwinput/inputmanagerimp.cpp | 16 ++++++++++++++-- apps/openmw/mwinput/inputmanagerimp.hpp | 6 ++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9524381fbf..f13eb9daf7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -450,7 +450,7 @@ namespace MWInput { mInputCtrl->mousePressed (arg, id); - MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0) { @@ -468,7 +468,7 @@ namespace MWInput { mInputCtrl->mouseReleased (arg, id); - MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, MyGUI::MouseButton::Enum(id)); + MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); return true; } @@ -905,4 +905,16 @@ namespace MWInput { loadKeyDefaults(true); } + + MyGUI::MouseButton InputManager::sdlButtonToMyGUI(Uint8 button) + { + //The right button is the second button, according to MyGUI + if(button == SDL_BUTTON_RIGHT) + button = SDL_BUTTON_MIDDLE; + else if(button == SDL_BUTTON_MIDDLE) + button = SDL_BUTTON_RIGHT; + + //MyGUI's buttons are 0 indexed + return MyGUI::MouseButton::Enum(button - 1); + } } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 3677f9070a..df6ce3c434 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -36,6 +36,11 @@ namespace ICS class InputControlSystem; } +namespace MyGUI +{ + class MouseButton; +} + #include #include #include @@ -149,6 +154,7 @@ namespace MWInput private: void adjustMouseRegion(int width, int height); + MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button); void resetIdleTime(); void updateIdleTime(float dt); From 1bf36c686c5fd2c85eff2be5e08933a48df79c20 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 06:09:47 -0400 Subject: [PATCH 0005/1537] add ability to check if a window is on the stack (to see if we're in the main menu) --- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 8 ++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 1 + 3 files changed, 10 insertions(+) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 30bfced06a..13a35b5926 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -88,6 +88,7 @@ namespace MWBase ///< can be anywhere in the stack virtual MWGui::GuiMode getMode() const = 0; + virtual bool containsMode(MWGui::GuiMode) const = 0; virtual bool isGuiMode() const = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8ec495550e..d653b578ad 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -965,6 +965,14 @@ MWGui::GuiMode WindowManager::getMode() const return mGuiModes.back(); } +bool WindowManager::containsMode(GuiMode mode) const +{ + if(mGuiModes.empty()) + return false; + + return std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end(); +} + std::map > WindowManager::getPlayerSkillValues() { return mPlayerSkillValues; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8bcb88e224..e2a9666607 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -97,6 +97,7 @@ namespace MWGui virtual void removeGuiMode(GuiMode mode); ///< can be anywhere in the stack virtual GuiMode getMode() const; + virtual bool containsMode(GuiMode mode) const; virtual bool isGuiMode() const; From 02ccb758949b64abe026766e141a562d53313feb Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 06:10:05 -0400 Subject: [PATCH 0006/1537] Wrap the mouse to the window (except in debug mode) Grab the mouse when not in the main menu (except in debug mode) Always hide the cursor when it's over the window Allow warping the mouse around Handle ^C properly --- apps/openmw/mwinput/inputmanagerimp.cpp | 75 +++++------ apps/openmw/mwinput/inputmanagerimp.hpp | 5 + apps/openmw/mwinput/sdlinputwrapper.cpp | 170 ++++++++++++++++++------ apps/openmw/mwinput/sdlinputwrapper.hpp | 22 ++- extern/oics/OISCompat.h | 12 ++ 5 files changed, 194 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f13eb9daf7..805f4926c1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -44,6 +44,7 @@ namespace MWInput , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) + , mDebug(debug) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -52,50 +53,6 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) { - Ogre::RenderWindow* window = ogre.getWindow (); - size_t windowHnd; - - resetIdleTime(); - - window->getCustomAttribute("WINDOW", &windowHnd); - - - // Set non-exclusive mouse and keyboard input if the user requested - // it. - - //TODO: re-enable this and make it work with SDL - /* - - std::ostringstream windowHndStr; - OIS::ParamList pl; - - windowHndStr << windowHnd; - pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); - - if (debug) - { - #if defined OIS_WIN32_PLATFORM - pl.insert(std::make_pair(std::string("w32_mouse"), - std::string("DISCL_FOREGROUND" ))); - pl.insert(std::make_pair(std::string("w32_mouse"), - std::string("DISCL_NONEXCLUSIVE"))); - pl.insert(std::make_pair(std::string("w32_keyboard"), - std::string("DISCL_FOREGROUND"))); - pl.insert(std::make_pair(std::string("w32_keyboard"), - std::string("DISCL_NONEXCLUSIVE"))); - #elif defined OIS_LINUX_PLATFORM - pl.insert(std::make_pair(std::string("x11_mouse_grab"), - std::string("false"))); - pl.insert(std::make_pair(std::string("x11_mouse_hide"), - std::string("false"))); - pl.insert(std::make_pair(std::string("x11_keyboard_grab"), - std::string("false"))); - pl.insert(std::make_pair(std::string("XAutoRepeatOn"), - std::string("true"))); - #endif - } - */ - #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events ProcessSerialNumber psn = { 0, kCurrentProcess }; @@ -103,9 +60,12 @@ namespace MWInput SetFrontProcess(&psn); #endif + Ogre::RenderWindow* window = ogre.getWindow (); + mInputManager = new MWSDLInputWrapper(window); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); + mInputManager->setWindowEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -256,6 +216,15 @@ namespace MWInput // event callbacks (which may crash) mWindows.update(); + if(!mDebug) + { + //don't keep the pointer away from the window edge in GUI mode + mInputManager->setWrapPointer(!mWindows.isGuiMode()); + + //we let the mouse escape in the main menu + mInputManager->setGrabPointer(!mWindows.containsMode(MWGui::GM_MainMenu)); + } + // Disable movement in Gui mode if (mWindows.isGuiMode()) return; @@ -510,6 +479,24 @@ namespace MWInput return true; } + bool InputManager::windowFocusChange(bool have_focus) + { + if(!mDebug) + { + + } + return true; + } + + bool InputManager::windowVisibilityChange(bool visible) + { + if(!mDebug) + { + //TODO: Pause game? + } + return true; + } + void InputManager::toggleMainMenu() { if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index df6ce3c434..9a7656a67b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -55,6 +55,7 @@ namespace MWInput public MWBase::InputManager, public ICS::MWSDLKeyListener, public ICS::MWSDLMouseListener, + public ICS::MWSDLWindowListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -94,6 +95,9 @@ namespace MWInput virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); + virtual bool windowVisibilityChange( bool visible ); + virtual bool windowFocusChange( bool have_focus ); + virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control @@ -145,6 +149,7 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDebug; float mMouseX; float mMouseY; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 61fc3fc8b8..c8922cf3a5 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -3,6 +3,7 @@ #include #include +#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -14,7 +15,11 @@ namespace MWInput { MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : - mWindow(window), mStarted(false), mSDLWindow(NULL) + mWindow(window), + mSDLWindow(NULL), + mWarpCompensate(false), + mWrapPointer(false), + mGrabPointer(false) { _start(); } @@ -26,44 +31,7 @@ namespace MWInput SDL_Quit(); } - void MWSDLInputWrapper::capture() - { - _start(); - - SDL_Event evt; - while(SDL_PollEvent(&evt)) - { - switch(evt.type) - { - case SDL_MOUSEMOTION: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); - break; - case SDL_MOUSEWHEEL: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); - break; - case SDL_MOUSEBUTTONDOWN: - mMouseListener->mousePressed(evt.button, evt.button.button); - break; - case SDL_MOUSEBUTTONUP: - mMouseListener->mouseReleased(evt.button, evt.button.button); - break; - - case SDL_KEYDOWN: - mKeyboardListener->keyPressed(evt.key); - break; - case SDL_KEYUP: - mKeyboardListener->keyReleased(evt.key); - break; - } - } - } - - bool MWSDLInputWrapper::isModifierHeld(int mod) - { - return SDL_GetModState() & mod; - } - - void MWSDLInputWrapper::_start() + bool MWSDLInputWrapper::_start() { Uint32 flags = SDL_INIT_VIDEO; if(SDL_WasInit(flags) == 0) @@ -74,11 +42,15 @@ namespace MWInput //kindly ask SDL not to trash our OGL context SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - SDL_Init(SDL_INIT_VIDEO); + if(SDL_Init(SDL_INIT_VIDEO) != 0) + return false; //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + if(mSDLWindow == NULL) + return false; + #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups SDL_SysWMinfo wm_info; @@ -86,8 +58,6 @@ namespace MWInput if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) { - printf("SDL version %d.%d.%d\n", wm_info.version.major, wm_info.version.minor, wm_info.version.patch); - Display* display = wm_info.info.x11.display; Window w = wm_info.info.x11.window; @@ -111,6 +81,122 @@ namespace MWInput XFlush(display); } #endif + SDL_ShowCursor(SDL_FALSE); + } + + return true; + } + + void MWSDLInputWrapper::capture() + { + if(!_start()) + throw std::runtime_error(SDL_GetError()); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + //ignore this if it happened due to a warp + if(!_handleWarpMotion(evt.motion)) + { + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); + + //try to keep the mouse inside the window + _wrapMousePointer(evt.motion); + } + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + mKeyboardListener->keyPressed(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + mWindowListener->windowFocusChange(true); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + mWindowListener->windowFocusChange(false); + break; + case SDL_WINDOWEVENT_EXPOSED: + mWindowListener->windowVisibilityChange(true); + break; + case SDL_WINDOWEVENT_HIDDEN: + mWindowListener->windowVisibilityChange(false); + break; + + //SDL traps ^C signals, pass it to OGRE. + case SDL_QUIT: + Ogre::Root::getSingleton().queueEndRendering(); + break; + } + } + } + + bool MWSDLInputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void MWSDLInputWrapper::warpMouse(int x, int y) + { + SDL_WarpMouseInWindow(mSDLWindow, x, y); + mWarpCompensate = true; + mWarpX = x; + mWarpY = y; + } + + void MWSDLInputWrapper::setGrabPointer(bool grab) + { + SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; + + mGrabPointer = grab; + SDL_SetWindowGrab(mSDLWindow, sdlGrab); + } + + bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) + { + if(!mWarpCompensate) return false; + + //this was a warp event, signal the caller to eat it. + if(evt.x == mWarpX && evt.y == mWarpY) + { + mWarpCompensate = false; + return true; + } + + return false; + } + + void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) + { + if(!mWrapPointer || !mGrabPointer) return; + + int width = 0; + int height = 0; + + SDL_GetWindowSize(mSDLWindow, &width, &height); + + const int FUDGE_FACTOR_X = width / 4; + const int FUDGE_FACTOR_Y = height / 4; + + //warp the mouse if it's about to go outside the window + if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width + || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) + { + warpMouse(width / 2, height / 2); } } } diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index ee07efbdb4..d507073b86 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -16,19 +16,33 @@ namespace MWInput void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } + void setWindowEventCallback(ICS::MWSDLWindowListener* listen) { mWindowListener = listen; } void capture(); bool isModifierHeld(int mod); + void setWrapPointer(bool wrap) { mWrapPointer = wrap; } + void setGrabPointer(bool grab); + + void warpMouse(int x, int y); private: + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); + void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + + bool _start(); + ICS::MWSDLMouseListener* mMouseListener; ICS::MWSDLKeyListener* mKeyboardListener; + ICS::MWSDLWindowListener* mWindowListener; + + Uint16 mWarpX; + Uint16 mWarpY; + bool mWarpCompensate; + bool mWrapPointer; + bool mGrabPointer; + Ogre::RenderWindow* mWindow; SDL_Window* mSDLWindow; - - bool mStarted; - void _start(); - }; } diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index e8fd6904cb..5813c17bfd 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -91,5 +91,17 @@ public: virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} }; +class MWSDLWindowListener +{ +public: + virtual ~MWSDLWindowListener() {} + + /** @remarks The window's visibility changed */ + virtual bool windowVisibilityChange( bool visible ) = 0; + + /** @remarks The window got / lost input focus */ + virtual bool windowFocusChange( bool have_focus ) = 0; +}; + } #endif From 53cff0ba68f72d49834c9effbf1771a05a9d9a42 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 09:05:47 -0400 Subject: [PATCH 0007/1537] use native relative mouse movements where available, have the cursor follow the hardware cursor in the main menu --- apps/openmw/mwinput/inputmanagerimp.cpp | 40 ++++++++++++++++++++----- apps/openmw/mwinput/sdlinputwrapper.cpp | 37 ++++++++++++++++++++--- apps/openmw/mwinput/sdlinputwrapper.hpp | 4 ++- 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 805f4926c1..17251aff5a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -218,11 +218,23 @@ namespace MWInput if(!mDebug) { - //don't keep the pointer away from the window edge in GUI mode - mInputManager->setWrapPointer(!mWindows.isGuiMode()); + bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu); + + bool was_relative = mInputManager->getMouseRelative(); + bool is_relative = !main_menu; + + //don't keep the pointer away from the window edge in the main menu + mInputManager->setMouseRelative(is_relative); + + //we switched to non-relative mode, move our cursor to where the in-game + //cursor is + if( !is_relative && was_relative != is_relative ) + { + mInputManager->warpMouse(mMouseX, mMouseY); + } //we let the mouse escape in the main menu - mInputManager->setGrabPointer(!mWindows.containsMode(MWGui::GM_MainMenu)); + mInputManager->setGrabPointer(!main_menu); } // Disable movement in Gui mode @@ -454,8 +466,19 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - mMouseX += float(arg.xrel) * mUISensitivity; - mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; + + //FIXME: Except in the main menu, since we let the pointer escape + if(!mWindows.containsMode(MWGui::GM_MainMenu)) + { + mMouseX += float(arg.xrel) * mUISensitivity; + mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; + } + else + { + mMouseX = arg.x; + mMouseY = arg.y; + } + mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); @@ -499,10 +522,11 @@ namespace MWInput void InputManager::toggleMainMenu() { - if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) - mWindows.popGuiMode(); - else if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) + //TODO: should this be here? + if (mWindows.isGuiMode () && mWindows.getMode () == MWGui::GM_Video) MWBase::Environment::get().getWorld ()->stopVideo (); + else if (mWindows.containsMode(MWGui::GM_MainMenu)) + mWindows.popGuiMode(); else mWindows.pushGuiMode (MWGui::GM_MainMenu); } diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index c8922cf3a5..32f453b0f0 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -18,8 +18,9 @@ namespace MWInput mWindow(window), mSDLWindow(NULL), mWarpCompensate(false), - mWrapPointer(false), - mGrabPointer(false) + mMouseRelative(false), + mGrabPointer(false), + mWrapPointer(false) { _start(); } @@ -166,9 +167,34 @@ namespace MWInput SDL_SetWindowGrab(mSDLWindow, sdlGrab); } + void MWSDLInputWrapper::setMouseRelative(bool relative) + { + if(mMouseRelative == relative) + return; + + mMouseRelative = relative; + + mWrapPointer = false; + + //eep, wrap the pointer manually if the input driver doesn't support + //relative positioning natively + if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) + { + if(relative) + mWrapPointer = true; + } + + //now remove all mouse events using the old setting from the queue + SDL_PumpEvents(); + + SDL_Event dummy[20]; + SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + } + bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) { - if(!mWarpCompensate) return false; + if(!mWarpCompensate) + return false; //this was a warp event, signal the caller to eat it. if(evt.x == mWarpX && evt.y == mWarpY) @@ -182,7 +208,10 @@ namespace MWInput void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) { - if(!mWrapPointer || !mGrabPointer) return; + //don't wrap if we don't want relative movements, support relative + //movements natively, or aren't grabbing anyways + if(!mMouseRelative || !mWrapPointer || !mGrabPointer) + return; int width = 0; int height = 0; diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index d507073b86..c2770ae7e9 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -21,7 +21,8 @@ namespace MWInput void capture(); bool isModifierHeld(int mod); - void setWrapPointer(bool wrap) { mWrapPointer = wrap; } + void setMouseRelative(bool relative); + bool getMouseRelative() { return mMouseRelative; } void setGrabPointer(bool grab); void warpMouse(int x, int y); @@ -38,6 +39,7 @@ namespace MWInput Uint16 mWarpX; Uint16 mWarpY; bool mWarpCompensate; + bool mMouseRelative; bool mWrapPointer; bool mGrabPointer; From cb01df49c01f8e1391c62d3a1fd0a64b51bc81ff Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Wed, 9 Jan 2013 11:30:33 -0400 Subject: [PATCH 0008/1537] begin to support text input --- apps/openmw/mwinput/inputmanagerimp.cpp | 1 + apps/openmw/mwinput/sdlinputwrapper.cpp | 27 +++++++++++++++++++++++-- apps/openmw/mwinput/sdlinputwrapper.hpp | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 17251aff5a..763e75ae7f 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -413,6 +413,7 @@ namespace MWInput } #endif */ + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.keysym.sym), text); return true; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 32f453b0f0..56b3568f5c 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -27,8 +27,10 @@ namespace MWInput MWSDLInputWrapper::~MWSDLInputWrapper() { - SDL_DestroyWindow(mSDLWindow); + if(mSDLWindow != NULL) + SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; + SDL_StopTextInput(); SDL_Quit(); } @@ -52,6 +54,8 @@ namespace MWInput if(mSDLWindow == NULL) return false; + SDL_StartTextInput(); + #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups SDL_SysWMinfo wm_info; @@ -119,7 +123,7 @@ namespace MWInput break; case SDL_KEYDOWN: - mKeyboardListener->keyPressed(evt.key); + _handleKeyPress(evt.key); break; case SDL_KEYUP: mKeyboardListener->keyReleased(evt.key); @@ -228,4 +232,23 @@ namespace MWInput warpMouse(width / 2, height / 2); } } + + void MWSDLInputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) + { + //SDL keyboard events are followed by the actual text those keys would generate + //to account for languages that require multiple keystrokes to produce a key. + //Look for an event immediately following ours, assuming each key produces exactly + //one character. + + //TODO: This won't work for multibyte characters, but MyGUI is the only consumer + //of these, does it even support multibyte characters? + + SDL_Event text_evts[1]; + if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) + { + evt.keysym.unicode = text_evts[0].text.text[0]; + } + + mKeyboardListener->keyPressed(evt); + } } diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index c2770ae7e9..6377d0bcf9 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -30,6 +30,8 @@ namespace MWInput bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + void _handleKeyPress(SDL_KeyboardEvent& evt); + bool _start(); ICS::MWSDLMouseListener* mMouseListener; From ed644259ce71df3a3c61e54d8f92ebf6bfedfe14 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 17:21:47 -0400 Subject: [PATCH 0009/1537] Move SDL helpers to their own package in extern/, allow conversion from sdl to ois keycodes, (maybe) fix unicode handling --- CMakeLists.txt | 1 + apps/openmw/CMakeLists.txt | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 76 ++-- apps/openmw/mwinput/inputmanagerimp.hpp | 15 +- apps/openmw/mwinput/sdlinputwrapper.cpp | 254 ----------- apps/openmw/mwinput/sdlinputwrapper.hpp | 53 --- extern/oics/CMakeLists.txt | 1 - extern/oics/ICSInputControlSystem.h | 10 +- extern/oics/ICSInputControlSystem_mouse.cpp | 2 +- extern/sdl4ogre/CMakeLists.txt | 14 + extern/sdl4ogre/OISCompat.h | 159 +++++++ .../{oics/OISCompat.h => sdl4ogre/events.h} | 66 +-- extern/sdl4ogre/sdlinputwrapper.cpp | 420 ++++++++++++++++++ extern/sdl4ogre/sdlinputwrapper.hpp | 67 +++ 14 files changed, 733 insertions(+), 408 deletions(-) delete mode 100644 apps/openmw/mwinput/sdlinputwrapper.cpp delete mode 100644 apps/openmw/mwinput/sdlinputwrapper.hpp create mode 100644 extern/sdl4ogre/CMakeLists.txt create mode 100644 extern/sdl4ogre/OISCompat.h rename extern/{oics/OISCompat.h => sdl4ogre/events.h} (53%) create mode 100644 extern/sdl4ogre/sdlinputwrapper.cpp create mode 100644 extern/sdl4ogre/sdlinputwrapper.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index de4be3895f..37023571bb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -474,6 +474,7 @@ endif(WIN32) # Extern add_subdirectory (extern/shiny) add_subdirectory (extern/oics) +add_subdirectory (extern/sdl4ogre) # Components add_subdirectory (components) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 4aa744e3b3..faab842c35 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -20,7 +20,7 @@ add_openmw_dir (mwrender ) add_openmw_dir (mwinput - inputmanagerimp sdlinputwrapper + inputmanagerimp ) add_openmw_dir (mwgui @@ -108,6 +108,7 @@ target_link_libraries(openmw "shiny" "shiny.OgrePlatform" "oics" + "sdl4ogre" components ) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 763e75ae7f..6d25f7dc66 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -62,13 +62,13 @@ namespace MWInput Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new MWSDLInputWrapper(window); + mInputManager = new SFO::InputWrapper(window); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); std::string file = userFileExists ? userFile : ""; - mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); + mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); adjustMouseRegion (window->getWidth(), window->getHeight()); @@ -78,7 +78,7 @@ namespace MWInput for (int i = 0; i < A_Last; ++i) { - mInputCtrl->getChannel (i)->addListener (this); + mInputBinder->getChannel (i)->addListener (this); } mControlSwitch["playercontrols"] = true; @@ -94,9 +94,9 @@ namespace MWInput InputManager::~InputManager() { - mInputCtrl->save (mUserFile); + mInputBinder->save (mUserFile); - delete mInputCtrl; + delete mInputBinder; delete mInputManager; } @@ -206,7 +206,7 @@ namespace MWInput // update values of channels (as a result of pressed keys) if (!loading) - mInputCtrl->update(dt); + mInputBinder->update(dt); // Update windows/gui as a result of input events // For instance this could mean opening a new window/dialog, @@ -396,12 +396,12 @@ namespace MWInput void InputManager::adjustMouseRegion(int width, int height) { - mInputCtrl->adjustMouseRegion(width, height); + mInputBinder->adjustMouseRegion(width, height); } bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { - mInputCtrl->keyPressed (arg); + mInputBinder->keyPressed (arg); unsigned int text = arg.keysym.unicode; //TODO: Check if we need this with SDL @@ -414,23 +414,27 @@ namespace MWInput #endif */ - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(arg.keysym.sym), text); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), text); return true; } bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - mInputCtrl->keyReleased (arg); + mInputBinder->keyReleased (arg); - MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(arg.keysym.sym)); + OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); + + MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)); return true; } bool InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputCtrl->mousePressed (arg, id); + mInputBinder->mousePressed (arg, id); MyGUI::InputManager::getInstance().injectMousePress(mMouseX, mMouseY, sdlButtonToMyGUI(id)); @@ -448,16 +452,16 @@ namespace MWInput bool InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) { - mInputCtrl->mouseReleased (arg, id); + mInputBinder->mouseReleased (arg, id); MyGUI::InputManager::getInstance().injectMouseRelease(mMouseX, mMouseY, sdlButtonToMyGUI(id)); return true; } - bool InputManager::mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ) + bool InputManager::mouseMoved(const SFO::MouseMotionEvent &arg ) { - mInputCtrl->mouseMoved (arg); + mInputBinder->mouseMoved (arg); resetIdleTime (); @@ -683,7 +687,7 @@ namespace MWInput bool InputManager::actionIsActive (int id) { - return mInputCtrl->getChannel (id)->getValue () == 1; + return mInputBinder->getChannel (id)->getValue () == 1; } void InputManager::loadKeyDefaults (bool force) @@ -728,29 +732,29 @@ namespace MWInput for (int i = 0; i < A_Last; ++i) { ICS::Control* control; - bool controlExists = mInputCtrl->getChannel(i)->getControlsCount () != 0; + bool controlExists = mInputBinder->getChannel(i)->getControlsCount () != 0; if (!controlExists) { control = new ICS::Control(boost::lexical_cast(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX); - mInputCtrl->addControl(control); - control->attachChannel(mInputCtrl->getChannel(i), ICS::Channel::DIRECT); + mInputBinder->addControl(control); + control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT); } else { - control = mInputCtrl->getChannel(i)->getAttachedControls ().front().control; + control = mInputBinder->getChannel(i)->getAttachedControls ().front().control; } if (!controlExists || force || - ( mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) == SDLK_UNKNOWN - && mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS + ( mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) == SDLK_UNKNOWN + && mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS )) { clearAllBindings (control); if (defaultKeyBindings.find(i) != defaultKeyBindings.end()) - mInputCtrl->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); + mInputBinder->addKeyBinding(control, static_cast(defaultKeyBindings[i]), ICS::Control::INCREASE); else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()) - mInputCtrl->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); + mInputBinder->addMouseButtonBinding (control, defaultMouseButtonBindings[i], ICS::Control::INCREASE); } } } @@ -794,15 +798,15 @@ namespace MWInput std::string InputManager::getActionBindingName (int action) { - if (mInputCtrl->getChannel (action)->getControlsCount () == 0) + if (mInputBinder->getChannel (action)->getControlsCount () == 0) return "#{sNone}"; - ICS::Control* c = mInputCtrl->getChannel (action)->getAttachedControls ().front().control; + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - if (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE) != SDLK_UNKNOWN) - return mInputCtrl->keyCodeToString (mInputCtrl->getKeyBinding (c, ICS::Control::INCREASE)); - else if (mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) - return "#{sMouse} " + boost::lexical_cast(mInputCtrl->getMouseButtonBinding (c, ICS::Control::INCREASE)); + if (mInputBinder->getKeyBinding (c, ICS::Control::INCREASE) != SDLK_UNKNOWN) + return mInputBinder->keyCodeToString (mInputBinder->getKeyBinding (c, ICS::Control::INCREASE)); + else if (mInputBinder->getMouseButtonBinding (c, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + return "#{sMouse} " + boost::lexical_cast(mInputBinder->getMouseButtonBinding (c, ICS::Control::INCREASE)); else return "#{sNone}"; } @@ -842,9 +846,9 @@ namespace MWInput void InputManager::enableDetectingBindingMode (int action) { - ICS::Control* c = mInputCtrl->getChannel (action)->getAttachedControls ().front().control; + ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control; - mInputCtrl->enableDetectingBindingState (c, ICS::Control::INCREASE); + mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE); } void InputManager::mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control @@ -905,10 +909,10 @@ namespace MWInput void InputManager::clearAllBindings (ICS::Control* control) { // right now we don't really need multiple bindings for the same action, so remove all others first - if (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE) != SDLK_UNKNOWN) - mInputCtrl->removeKeyBinding (mInputCtrl->getKeyBinding (control, ICS::Control::INCREASE)); - if (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) - mInputCtrl->removeMouseButtonBinding (mInputCtrl->getMouseButtonBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDLK_UNKNOWN) + mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE)); + if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS) + mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE)); /// \todo add joysticks here once they are added } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 9a7656a67b..34ea92a374 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -6,7 +6,7 @@ #include #include "../mwbase/inputmanager.hpp" -#include "sdlinputwrapper.hpp" +#include namespace OEngine { @@ -43,7 +43,6 @@ namespace MyGUI #include #include -#include namespace MWInput { @@ -53,9 +52,9 @@ namespace MWInput */ class InputManager : public MWBase::InputManager, - public ICS::MWSDLKeyListener, - public ICS::MWSDLMouseListener, - public ICS::MWSDLWindowListener, + public SFO::KeyListener, + public SFO::MouseListener, + public SFO::WindowListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -93,7 +92,7 @@ namespace MWInput virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); - virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); + virtual bool mouseMoved( const SFO::MouseMotionEvent &arg ); virtual bool windowVisibilityChange( bool visible ); virtual bool windowFocusChange( bool have_focus ); @@ -129,10 +128,10 @@ namespace MWInput MWBase::WindowManager &mWindows; OMW::Engine& mEngine; - ICS::InputControlSystem* mInputCtrl; + ICS::InputControlSystem* mInputBinder; - MWSDLInputWrapper* mInputManager; + SFO::InputWrapper* mInputManager; std::string mUserFile; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp deleted file mode 100644 index 56b3568f5c..0000000000 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ /dev/null @@ -1,254 +0,0 @@ -#include "sdlinputwrapper.hpp" -#include -#include - -#include -#include - -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX -# include -# include -# include -#endif - - -namespace MWInput -{ - MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : - mWindow(window), - mSDLWindow(NULL), - mWarpCompensate(false), - mMouseRelative(false), - mGrabPointer(false), - mWrapPointer(false) - { - _start(); - } - - MWSDLInputWrapper::~MWSDLInputWrapper() - { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; - SDL_StopTextInput(); - SDL_Quit(); - } - - bool MWSDLInputWrapper::_start() - { - Uint32 flags = SDL_INIT_VIDEO; - if(SDL_WasInit(flags) == 0) - { - //get the HWND from ogre's renderwindow - size_t windowHnd; - mWindow->getCustomAttribute("WINDOW", &windowHnd); - - //kindly ask SDL not to trash our OGL context - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(SDL_INIT_VIDEO) != 0) - return false; - - //wrap our own event handler around ogre's - mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); - - if(mSDLWindow == NULL) - return false; - - SDL_StartTextInput(); - -#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - //linux-specific event-handling fixups - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); - - if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) - { - Display* display = wm_info.info.x11.display; - Window w = wm_info.info.x11.window; - - // Set the input hints so we get keyboard input - XWMHints *wmhints = XAllocWMHints(); - if (wmhints) { - wmhints->input = True; - wmhints->flags = InputHint; - XSetWMHints(display, w, wmhints); - XFree(wmhints); - } - - //make sure to subscribe to XLib's events - XSelectInput(display, w, - (FocusChangeMask | EnterWindowMask | LeaveWindowMask | - ExposureMask | ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | KeyPressMask | KeyReleaseMask | - PropertyChangeMask | StructureNotifyMask | - KeymapStateMask)); - - XFlush(display); - } -#endif - SDL_ShowCursor(SDL_FALSE); - } - - return true; - } - - void MWSDLInputWrapper::capture() - { - if(!_start()) - throw std::runtime_error(SDL_GetError()); - - SDL_Event evt; - while(SDL_PollEvent(&evt)) - { - switch(evt.type) - { - case SDL_MOUSEMOTION: - //ignore this if it happened due to a warp - if(!_handleWarpMotion(evt.motion)) - { - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); - - //try to keep the mouse inside the window - _wrapMousePointer(evt.motion); - } - break; - case SDL_MOUSEWHEEL: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); - break; - case SDL_MOUSEBUTTONDOWN: - mMouseListener->mousePressed(evt.button, evt.button.button); - break; - case SDL_MOUSEBUTTONUP: - mMouseListener->mouseReleased(evt.button, evt.button.button); - break; - - case SDL_KEYDOWN: - _handleKeyPress(evt.key); - break; - case SDL_KEYUP: - mKeyboardListener->keyReleased(evt.key); - break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - mWindowListener->windowFocusChange(true); - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - mWindowListener->windowFocusChange(false); - break; - case SDL_WINDOWEVENT_EXPOSED: - mWindowListener->windowVisibilityChange(true); - break; - case SDL_WINDOWEVENT_HIDDEN: - mWindowListener->windowVisibilityChange(false); - break; - - //SDL traps ^C signals, pass it to OGRE. - case SDL_QUIT: - Ogre::Root::getSingleton().queueEndRendering(); - break; - } - } - } - - bool MWSDLInputWrapper::isModifierHeld(int mod) - { - return SDL_GetModState() & mod; - } - - void MWSDLInputWrapper::warpMouse(int x, int y) - { - SDL_WarpMouseInWindow(mSDLWindow, x, y); - mWarpCompensate = true; - mWarpX = x; - mWarpY = y; - } - - void MWSDLInputWrapper::setGrabPointer(bool grab) - { - SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; - - mGrabPointer = grab; - SDL_SetWindowGrab(mSDLWindow, sdlGrab); - } - - void MWSDLInputWrapper::setMouseRelative(bool relative) - { - if(mMouseRelative == relative) - return; - - mMouseRelative = relative; - - mWrapPointer = false; - - //eep, wrap the pointer manually if the input driver doesn't support - //relative positioning natively - if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) - { - if(relative) - mWrapPointer = true; - } - - //now remove all mouse events using the old setting from the queue - SDL_PumpEvents(); - - SDL_Event dummy[20]; - SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); - } - - bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) - { - if(!mWarpCompensate) - return false; - - //this was a warp event, signal the caller to eat it. - if(evt.x == mWarpX && evt.y == mWarpY) - { - mWarpCompensate = false; - return true; - } - - return false; - } - - void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) - { - //don't wrap if we don't want relative movements, support relative - //movements natively, or aren't grabbing anyways - if(!mMouseRelative || !mWrapPointer || !mGrabPointer) - return; - - int width = 0; - int height = 0; - - SDL_GetWindowSize(mSDLWindow, &width, &height); - - const int FUDGE_FACTOR_X = width / 4; - const int FUDGE_FACTOR_Y = height / 4; - - //warp the mouse if it's about to go outside the window - if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width - || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) - { - warpMouse(width / 2, height / 2); - } - } - - void MWSDLInputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) - { - //SDL keyboard events are followed by the actual text those keys would generate - //to account for languages that require multiple keystrokes to produce a key. - //Look for an event immediately following ours, assuming each key produces exactly - //one character. - - //TODO: This won't work for multibyte characters, but MyGUI is the only consumer - //of these, does it even support multibyte characters? - - SDL_Event text_evts[1]; - if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) - { - evt.keysym.unicode = text_evts[0].text.text[0]; - } - - mKeyboardListener->keyPressed(evt); - } -} diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp deleted file mode 100644 index 6377d0bcf9..0000000000 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _MWINPUT_SDLINPUTWRAPPER_H -#define _MWINPUT_SDLINPUTWRAPPER_H - -#include "SDL2/SDL_events.h" -#include -#include - - -namespace MWInput -{ - class MWSDLInputWrapper - { - public: - MWSDLInputWrapper(Ogre::RenderWindow* window); - ~MWSDLInputWrapper(); - - void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } - void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } - void setWindowEventCallback(ICS::MWSDLWindowListener* listen) { mWindowListener = listen; } - - void capture(); - bool isModifierHeld(int mod); - - void setMouseRelative(bool relative); - bool getMouseRelative() { return mMouseRelative; } - void setGrabPointer(bool grab); - - void warpMouse(int x, int y); - private: - bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); - void _wrapMousePointer(const SDL_MouseMotionEvent &evt); - - void _handleKeyPress(SDL_KeyboardEvent& evt); - - bool _start(); - - ICS::MWSDLMouseListener* mMouseListener; - ICS::MWSDLKeyListener* mKeyboardListener; - ICS::MWSDLWindowListener* mWindowListener; - - Uint16 mWarpX; - Uint16 mWarpY; - bool mWarpCompensate; - bool mMouseRelative; - bool mWrapPointer; - bool mGrabPointer; - - Ogre::RenderWindow* mWindow; - SDL_Window* mSDLWindow; - }; -} - -#endif diff --git a/extern/oics/CMakeLists.txt b/extern/oics/CMakeLists.txt index 2e2a7a6d6b..7c14387a4b 100644 --- a/extern/oics/CMakeLists.txt +++ b/extern/oics/CMakeLists.txt @@ -9,7 +9,6 @@ set(OICS_SOURCE_FILES ICSInputControlSystem_keyboard.cpp ICSInputControlSystem_mouse.cpp ICSInputControlSystem_joystick.cpp - OISCompat.h tinyxml.cpp tinyxmlparser.cpp tinyxmlerror.cpp diff --git a/extern/oics/ICSInputControlSystem.h b/extern/oics/ICSInputControlSystem.h index 5d30b35cfb..f42f9c0b5f 100644 --- a/extern/oics/ICSInputControlSystem.h +++ b/extern/oics/ICSInputControlSystem.h @@ -32,7 +32,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ICSControl.h" #include "ICSChannel.h" -#include "OISCompat.h" +#include "../sdl4ogre/events.h" #define ICS_LOG(text) if(mLog) mLog->logMessage( ("ICS: " + std::string(text)).c_str() ); #define ICS_MAX_JOYSTICK_AXIS 16 @@ -50,9 +50,9 @@ namespace ICS }; class DllExport InputControlSystem : - public MWSDLMouseListener, - public MWSDLKeyListener, - public MWSDLJoyStickListener + public SFO::MouseListener, + public SFO::KeyListener, + public SFO::JoyListener { public: @@ -102,7 +102,7 @@ namespace ICS JoystickIDList& getJoystickIdList(){ return mJoystickIDList; }; // MouseListener - bool mouseMoved(const MWSDLMouseMotionEvent &evt); + bool mouseMoved(const SFO::MouseMotionEvent &evt); bool mousePressed(const SDL_MouseButtonEvent &evt, Uint8); bool mouseReleased(const SDL_MouseButtonEvent &evt, Uint8); diff --git a/extern/oics/ICSInputControlSystem_mouse.cpp b/extern/oics/ICSInputControlSystem_mouse.cpp index 96197426a9..52eb894ed5 100644 --- a/extern/oics/ICSInputControlSystem_mouse.cpp +++ b/extern/oics/ICSInputControlSystem_mouse.cpp @@ -219,7 +219,7 @@ namespace ICS } // mouse Listeners - bool InputControlSystem::mouseMoved(const MWSDLMouseMotionEvent& evt) + bool InputControlSystem::mouseMoved(const SFO::MouseMotionEvent& evt) { if(mActive) { diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt new file mode 100644 index 0000000000..c52dd4cb43 --- /dev/null +++ b/extern/sdl4ogre/CMakeLists.txt @@ -0,0 +1,14 @@ +set(SDL4OGRE_LIBRARY "sdl4ogre") + +# Sources + +set(SDL4OGRE_SOURCE_FILES + sdlinputwrapper.cpp +) + +add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES}) + +link_directories(${CMAKE_CURRENT_BINARY_DIR}) + + +target_link_libraries(${SDL4OGRE_LIBRARY} ${SDL2_LIBRARY}) diff --git a/extern/sdl4ogre/OISCompat.h b/extern/sdl4ogre/OISCompat.h new file mode 100644 index 0000000000..04ba2c537d --- /dev/null +++ b/extern/sdl4ogre/OISCompat.h @@ -0,0 +1,159 @@ +#ifndef _OIS_SDL_COMPAT_H +#define _OIS_SDL_COMPAT_H + +#include +#include + +namespace OIS +{ +//! Keyboard scan codes +enum KeyCode +{ + KC_UNASSIGNED = 0x00, + KC_ESCAPE = 0x01, + KC_1 = 0x02, + KC_2 = 0x03, + KC_3 = 0x04, + KC_4 = 0x05, + KC_5 = 0x06, + KC_6 = 0x07, + KC_7 = 0x08, + KC_8 = 0x09, + KC_9 = 0x0A, + KC_0 = 0x0B, + KC_MINUS = 0x0C, // - on main keyboard + KC_EQUALS = 0x0D, + KC_BACK = 0x0E, // backspace + KC_TAB = 0x0F, + KC_Q = 0x10, + KC_W = 0x11, + KC_E = 0x12, + KC_R = 0x13, + KC_T = 0x14, + KC_Y = 0x15, + KC_U = 0x16, + KC_I = 0x17, + KC_O = 0x18, + KC_P = 0x19, + KC_LBRACKET = 0x1A, + KC_RBRACKET = 0x1B, + KC_RETURN = 0x1C, // Enter on main keyboard + KC_LCONTROL = 0x1D, + KC_A = 0x1E, + KC_S = 0x1F, + KC_D = 0x20, + KC_F = 0x21, + KC_G = 0x22, + KC_H = 0x23, + KC_J = 0x24, + KC_K = 0x25, + KC_L = 0x26, + KC_SEMICOLON = 0x27, + KC_APOSTROPHE = 0x28, + KC_GRAVE = 0x29, // accent + KC_LSHIFT = 0x2A, + KC_BACKSLASH = 0x2B, + KC_Z = 0x2C, + KC_X = 0x2D, + KC_C = 0x2E, + KC_V = 0x2F, + KC_B = 0x30, + KC_N = 0x31, + KC_M = 0x32, + KC_COMMA = 0x33, + KC_PERIOD = 0x34, // . on main keyboard + KC_SLASH = 0x35, // / on main keyboard + KC_RSHIFT = 0x36, + KC_MULTIPLY = 0x37, // * on numeric keypad + KC_LMENU = 0x38, // left Alt + KC_SPACE = 0x39, + KC_CAPITAL = 0x3A, + KC_F1 = 0x3B, + KC_F2 = 0x3C, + KC_F3 = 0x3D, + KC_F4 = 0x3E, + KC_F5 = 0x3F, + KC_F6 = 0x40, + KC_F7 = 0x41, + KC_F8 = 0x42, + KC_F9 = 0x43, + KC_F10 = 0x44, + KC_NUMLOCK = 0x45, + KC_SCROLL = 0x46, // Scroll Lock + KC_NUMPAD7 = 0x47, + KC_NUMPAD8 = 0x48, + KC_NUMPAD9 = 0x49, + KC_SUBTRACT = 0x4A, // - on numeric keypad + KC_NUMPAD4 = 0x4B, + KC_NUMPAD5 = 0x4C, + KC_NUMPAD6 = 0x4D, + KC_ADD = 0x4E, // + on numeric keypad + KC_NUMPAD1 = 0x4F, + KC_NUMPAD2 = 0x50, + KC_NUMPAD3 = 0x51, + KC_NUMPAD0 = 0x52, + KC_DECIMAL = 0x53, // . on numeric keypad + KC_OEM_102 = 0x56, // < > | on UK/Germany keyboards + KC_F11 = 0x57, + KC_F12 = 0x58, + KC_F13 = 0x64, // (NEC PC98) + KC_F14 = 0x65, // (NEC PC98) + KC_F15 = 0x66, // (NEC PC98) + KC_KANA = 0x70, // (Japanese keyboard) + KC_ABNT_C1 = 0x73, // / ? on Portugese (Brazilian) keyboards + KC_CONVERT = 0x79, // (Japanese keyboard) + KC_NOCONVERT = 0x7B, // (Japanese keyboard) + KC_YEN = 0x7D, // (Japanese keyboard) + KC_ABNT_C2 = 0x7E, // Numpad . on Portugese (Brazilian) keyboards + KC_NUMPADEQUALS= 0x8D, // = on numeric keypad (NEC PC98) + KC_PREVTRACK = 0x90, // Previous Track (KC_CIRCUMFLEX on Japanese keyboard) + KC_AT = 0x91, // (NEC PC98) + KC_COLON = 0x92, // (NEC PC98) + KC_UNDERLINE = 0x93, // (NEC PC98) + KC_KANJI = 0x94, // (Japanese keyboard) + KC_STOP = 0x95, // (NEC PC98) + KC_AX = 0x96, // (Japan AX) + KC_UNLABELED = 0x97, // (J3100) + KC_NEXTTRACK = 0x99, // Next Track + KC_NUMPADENTER = 0x9C, // Enter on numeric keypad + KC_RCONTROL = 0x9D, + KC_MUTE = 0xA0, // Mute + KC_CALCULATOR = 0xA1, // Calculator + KC_PLAYPAUSE = 0xA2, // Play / Pause + KC_MEDIASTOP = 0xA4, // Media Stop + KC_VOLUMEDOWN = 0xAE, // Volume - + KC_VOLUMEUP = 0xB0, // Volume + + KC_WEBHOME = 0xB2, // Web home + KC_NUMPADCOMMA = 0xB3, // , on numeric keypad (NEC PC98) + KC_DIVIDE = 0xB5, // / on numeric keypad + KC_SYSRQ = 0xB7, + KC_RMENU = 0xB8, // right Alt + KC_PAUSE = 0xC5, // Pause + KC_HOME = 0xC7, // Home on arrow keypad + KC_UP = 0xC8, // UpArrow on arrow keypad + KC_PGUP = 0xC9, // PgUp on arrow keypad + KC_LEFT = 0xCB, // LeftArrow on arrow keypad + KC_RIGHT = 0xCD, // RightArrow on arrow keypad + KC_END = 0xCF, // End on arrow keypad + KC_DOWN = 0xD0, // DownArrow on arrow keypad + KC_PGDOWN = 0xD1, // PgDn on arrow keypad + KC_INSERT = 0xD2, // Insert on arrow keypad + KC_DELETE = 0xD3, // Delete on arrow keypad + KC_LWIN = 0xDB, // Left Windows key + KC_RWIN = 0xDC, // Right Windows key + KC_APPS = 0xDD, // AppMenu key + KC_POWER = 0xDE, // System Power + KC_SLEEP = 0xDF, // System Sleep + KC_WAKE = 0xE3, // System Wake + KC_WEBSEARCH = 0xE5, // Web Search + KC_WEBFAVORITES= 0xE6, // Web Favorites + KC_WEBREFRESH = 0xE7, // Web Refresh + KC_WEBSTOP = 0xE8, // Web Stop + KC_WEBFORWARD = 0xE9, // Web Forward + KC_WEBBACK = 0xEA, // Web Back + KC_MYCOMPUTER = 0xEB, // My Computer + KC_MAIL = 0xEC, // Mail + KC_MEDIASELECT = 0xED // Media Select +}; +} +#endif diff --git a/extern/oics/OISCompat.h b/extern/sdl4ogre/events.h similarity index 53% rename from extern/oics/OISCompat.h rename to extern/sdl4ogre/events.h index 5813c17bfd..945daf49a8 100644 --- a/extern/oics/OISCompat.h +++ b/extern/sdl4ogre/events.h @@ -1,53 +1,20 @@ -#ifndef _OIS_SDL_COMPAT_H -#define _OIS_SDL_COMPAT_H +#ifndef _SFO_EVENTS_H +#define _SFO_EVENTS_H -#include -#include +#include -//TODO: Remove this. Right now we want to remain as close to OIS as possible -//So we can easily test the SDL backend //////////// // Events // //////////// -namespace ICS { +namespace SFO { /** Extended mouse event struct where we treat the wheel like an axis, like everyone expects */ -struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { +struct MouseMotionEvent : SDL_MouseMotionEvent { - Sint16 zrel; - - MWSDLMouseMotionEvent() - { - _init(); - } - - MWSDLMouseMotionEvent( const SDL_MouseMotionEvent& evt) - { - _init(); - x = evt.x; - y = evt.y; - xrel = evt.xrel; - yrel = evt.yrel; - state = evt.state; - } - - MWSDLMouseMotionEvent (const SDL_MouseWheelEvent& evt) - { - _init(); - zrel = evt.y; - } - - void _init() - { - x = 0; - y = 0; - xrel = 0; - yrel = 0; - state = 0; - zrel = 0; - } + Sint32 zrel; + Sint32 z; }; @@ -55,27 +22,27 @@ struct MWSDLMouseMotionEvent : SDL_MouseMotionEvent { // Listeners // /////////////// -class MWSDLMouseListener +class MouseListener { public: - virtual ~MWSDLMouseListener() {} - virtual bool mouseMoved( const MWSDLMouseMotionEvent &arg ) = 0; + virtual ~MouseListener() {} + virtual bool mouseMoved( const MouseMotionEvent &arg ) = 0; virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ) = 0; }; -class MWSDLKeyListener +class KeyListener { public: - virtual ~MWSDLKeyListener() {} + virtual ~KeyListener() {} virtual bool keyPressed(const SDL_KeyboardEvent &arg) = 0; virtual bool keyReleased(const SDL_KeyboardEvent &arg) = 0; }; -class MWSDLJoyStickListener +class JoyListener { public: - virtual ~MWSDLJoyStickListener() {} + virtual ~JoyListener() {} /** @remarks Joystick button down event */ virtual bool buttonPressed( const SDL_JoyButtonEvent &evt, int button ) = 0; @@ -91,10 +58,10 @@ public: virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} }; -class MWSDLWindowListener +class WindowListener { public: - virtual ~MWSDLWindowListener() {} + virtual ~WindowListener() {} /** @remarks The window's visibility changed */ virtual bool windowVisibilityChange( bool visible ) = 0; @@ -104,4 +71,5 @@ public: }; } + #endif diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp new file mode 100644 index 0000000000..b7d1550c90 --- /dev/null +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -0,0 +1,420 @@ +#include "sdlinputwrapper.hpp" +#include + +#include +#include +#include + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +# include +# include +# include +#endif + + +namespace SFO +{ + InputWrapper::InputWrapper(Ogre::RenderWindow *window) : + mWindow(window), + mSDLWindow(NULL), + mWarpCompensate(false), + mMouseRelative(false), + mGrabPointer(false), + mWrapPointer(false), + mMouseZ(0), + mMouseY(0), + mMouseX(0) + { + _start(); + _setupOISKeys(); + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + SDL_StopTextInput(); + SDL_Quit(); + } + + bool InputWrapper::_start() + { + Uint32 flags = SDL_INIT_VIDEO; + if(SDL_WasInit(flags) == 0) + { + //get the HWND from ogre's renderwindow + size_t windowHnd; + mWindow->getCustomAttribute("WINDOW", &windowHnd); + + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(SDL_INIT_VIDEO) != 0) + return false; + + //wrap our own event handler around ogre's + mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + + if(mSDLWindow == NULL) + return false; + + SDL_StartTextInput(); + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX + //linux-specific event-handling fixups + //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 + SDL_SysWMinfo wm_info; + SDL_VERSION(&wm_info.version); + + if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) + { + Display* display = wm_info.info.x11.display; + Window w = wm_info.info.x11.window; + + // Set the input hints so we get keyboard input + XWMHints *wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + wmhints->flags = InputHint; + XSetWMHints(display, w, wmhints); + XFree(wmhints); + } + + //make sure to subscribe to XLib's events + XSelectInput(display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + XFlush(display); + } +#endif + SDL_ShowCursor(SDL_FALSE); + } + + return true; + } + + void InputWrapper::capture() + { + if(!_start()) + throw std::runtime_error(SDL_GetError()); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + //ignore this if it happened due to a warp + if(!_handleWarpMotion(evt.motion)) + { + mMouseListener->mouseMoved(_packageMouseMotion(evt)); + + //try to keep the mouse inside the window + _wrapMousePointer(evt.motion); + } + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(_packageMouseMotion(evt)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + _handleKeyPress(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + mWindowListener->windowFocusChange(true); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + mWindowListener->windowFocusChange(false); + break; + case SDL_WINDOWEVENT_EXPOSED: + mWindowListener->windowVisibilityChange(true); + break; + case SDL_WINDOWEVENT_HIDDEN: + mWindowListener->windowVisibilityChange(false); + break; + + //SDL traps ^C signals, pass it to OGRE. + case SDL_QUIT: + Ogre::Root::getSingleton().queueEndRendering(); + break; + } + } + } + + bool InputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void InputWrapper::warpMouse(int x, int y) + { + SDL_WarpMouseInWindow(mSDLWindow, x, y); + mWarpCompensate = true; + mWarpX = x; + mWarpY = y; + } + + void InputWrapper::setGrabPointer(bool grab) + { + SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; + + mGrabPointer = grab; + SDL_SetWindowGrab(mSDLWindow, sdlGrab); + } + + void InputWrapper::setMouseRelative(bool relative) + { + if(mMouseRelative == relative) + return; + + mMouseRelative = relative; + + mWrapPointer = false; + + //eep, wrap the pointer manually if the input driver doesn't support + //relative positioning natively + if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) + { + if(relative) + mWrapPointer = true; + } + + //now remove all mouse events using the old setting from the queue + SDL_PumpEvents(); + + SDL_Event dummy[20]; + SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + } + + bool InputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) + { + if(!mWarpCompensate) + return false; + + //this was a warp event, signal the caller to eat it. + if(evt.x == mWarpX && evt.y == mWarpY) + { + mWarpCompensate = false; + return true; + } + + return false; + } + + void InputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) + { + //don't wrap if we don't want relative movements, support relative + //movements natively, or aren't grabbing anyways + if(!mMouseRelative || !mWrapPointer || !mGrabPointer) + return; + + int width = 0; + int height = 0; + + SDL_GetWindowSize(mSDLWindow, &width, &height); + + const int FUDGE_FACTOR_X = width / 4; + const int FUDGE_FACTOR_Y = height / 4; + + //warp the mouse if it's about to go outside the window + if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width + || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) + { + warpMouse(width / 2, height / 2); + } + } + + void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) + { + //SDL keyboard events are followed by the actual text those keys would generate + //to account for languages that require multiple keystrokes to produce a key. + //Look for an event immediately following ours, assuming each key produces exactly + //one character or none at all. + + //TODO: Check if this works properly for multibyte symbols + //do we have to worry about endian-ness? + //for that matter, check if we even need to do any of this. + + SDL_Event text_evts[1]; + if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) + { + const char* symbol = text_evts[0].text.text; + + Uint32 num_bytes = strlen(symbol); + + //no valid character is more than 4 bytes + if(num_bytes > 0 && num_bytes <= 4) + { + Uint32 u32_symbol = boost::locale::conv::utf_to_utf(symbol)[0]; + + evt.keysym.unicode = u32_symbol; + } + } + + mKeyboardListener->keyPressed(evt); + } + + MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) + { + MouseMotionEvent pack_evt; + pack_evt.x = mMouseX; + pack_evt.xrel = 0; + pack_evt.y = mMouseY; + pack_evt.yrel = 0; + pack_evt.z = mMouseZ; + pack_evt.zrel = 0; + + if(evt.type == SDL_MOUSEMOTION) + { + pack_evt.x = mMouseX = evt.motion.x; + pack_evt.y = mMouseY = evt.motion.y; + pack_evt.xrel = evt.motion.xrel; + pack_evt.yrel = evt.motion.yrel; + } + else if(evt.type == SDL_MOUSEWHEEL) + { + mMouseZ += pack_evt.zrel = evt.wheel.y; + pack_evt.z = mMouseZ; + } + else + { + throw new std::runtime_error("Tried to package non-motion event!"); + } + + return pack_evt; + } + + OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code) + { + OIS::KeyCode kc = OIS::KC_UNASSIGNED; + + KeyMap::const_iterator ois_equiv = mKeyMap.find(code); + + if(ois_equiv != mKeyMap.end()) + kc = ois_equiv->second; + + return kc; + } + + void InputWrapper::_setupOISKeys() + { + //lifted from OIS's SDLKeyboard.cpp + mKeyMap.insert( KeyMap::value_type(SDLK_UNKNOWN, OIS::KC_UNASSIGNED)); + mKeyMap.insert( KeyMap::value_type(SDLK_ESCAPE, OIS::KC_ESCAPE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_1, OIS::KC_1) ); + mKeyMap.insert( KeyMap::value_type(SDLK_2, OIS::KC_2) ); + mKeyMap.insert( KeyMap::value_type(SDLK_3, OIS::KC_3) ); + mKeyMap.insert( KeyMap::value_type(SDLK_4, OIS::KC_4) ); + mKeyMap.insert( KeyMap::value_type(SDLK_5, OIS::KC_5) ); + mKeyMap.insert( KeyMap::value_type(SDLK_6, OIS::KC_6) ); + mKeyMap.insert( KeyMap::value_type(SDLK_7, OIS::KC_7) ); + mKeyMap.insert( KeyMap::value_type(SDLK_8, OIS::KC_8) ); + mKeyMap.insert( KeyMap::value_type(SDLK_9, OIS::KC_9) ); + mKeyMap.insert( KeyMap::value_type(SDLK_0, OIS::KC_0) ); + mKeyMap.insert( KeyMap::value_type(SDLK_MINUS, OIS::KC_MINUS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_EQUALS, OIS::KC_EQUALS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_BACKSPACE, OIS::KC_BACK) ); + mKeyMap.insert( KeyMap::value_type(SDLK_TAB, OIS::KC_TAB) ); + mKeyMap.insert( KeyMap::value_type(SDLK_q, OIS::KC_Q) ); + mKeyMap.insert( KeyMap::value_type(SDLK_w, OIS::KC_W) ); + mKeyMap.insert( KeyMap::value_type(SDLK_e, OIS::KC_E) ); + mKeyMap.insert( KeyMap::value_type(SDLK_r, OIS::KC_R) ); + mKeyMap.insert( KeyMap::value_type(SDLK_t, OIS::KC_T) ); + mKeyMap.insert( KeyMap::value_type(SDLK_y, OIS::KC_Y) ); + mKeyMap.insert( KeyMap::value_type(SDLK_u, OIS::KC_U) ); + mKeyMap.insert( KeyMap::value_type(SDLK_i, OIS::KC_I) ); + mKeyMap.insert( KeyMap::value_type(SDLK_o, OIS::KC_O) ); + mKeyMap.insert( KeyMap::value_type(SDLK_p, OIS::KC_P) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RETURN, OIS::KC_RETURN) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL)); + mKeyMap.insert( KeyMap::value_type(SDLK_a, OIS::KC_A) ); + mKeyMap.insert( KeyMap::value_type(SDLK_s, OIS::KC_S) ); + mKeyMap.insert( KeyMap::value_type(SDLK_d, OIS::KC_D) ); + mKeyMap.insert( KeyMap::value_type(SDLK_f, OIS::KC_F) ); + mKeyMap.insert( KeyMap::value_type(SDLK_g, OIS::KC_G) ); + mKeyMap.insert( KeyMap::value_type(SDLK_h, OIS::KC_H) ); + mKeyMap.insert( KeyMap::value_type(SDLK_j, OIS::KC_J) ); + mKeyMap.insert( KeyMap::value_type(SDLK_k, OIS::KC_K) ); + mKeyMap.insert( KeyMap::value_type(SDLK_l, OIS::KC_L) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SEMICOLON, OIS::KC_SEMICOLON) ); + mKeyMap.insert( KeyMap::value_type(SDLK_COLON, OIS::KC_COLON) ); + mKeyMap.insert( KeyMap::value_type(SDLK_QUOTE, OIS::KC_APOSTROPHE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_BACKQUOTE, OIS::KC_GRAVE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LSHIFT, OIS::KC_LSHIFT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_BACKSLASH, OIS::KC_BACKSLASH) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SLASH, OIS::KC_SLASH) ); + mKeyMap.insert( KeyMap::value_type(SDLK_z, OIS::KC_Z) ); + mKeyMap.insert( KeyMap::value_type(SDLK_x, OIS::KC_X) ); + mKeyMap.insert( KeyMap::value_type(SDLK_c, OIS::KC_C) ); + mKeyMap.insert( KeyMap::value_type(SDLK_v, OIS::KC_V) ); + mKeyMap.insert( KeyMap::value_type(SDLK_b, OIS::KC_B) ); + mKeyMap.insert( KeyMap::value_type(SDLK_n, OIS::KC_N) ); + mKeyMap.insert( KeyMap::value_type(SDLK_m, OIS::KC_M) ); + mKeyMap.insert( KeyMap::value_type(SDLK_COMMA, OIS::KC_COMMA) ); + mKeyMap.insert( KeyMap::value_type(SDLK_PERIOD, OIS::KC_PERIOD)); + mKeyMap.insert( KeyMap::value_type(SDLK_RSHIFT, OIS::KC_RSHIFT)); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_MULTIPLY, OIS::KC_MULTIPLY) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LALT, OIS::KC_LMENU) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SPACE, OIS::KC_SPACE)); + mKeyMap.insert( KeyMap::value_type(SDLK_CAPSLOCK, OIS::KC_CAPITAL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F1, OIS::KC_F1) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F2, OIS::KC_F2) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F3, OIS::KC_F3) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F4, OIS::KC_F4) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F5, OIS::KC_F5) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F6, OIS::KC_F6) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F7, OIS::KC_F7) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F8, OIS::KC_F8) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F9, OIS::KC_F9) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F10, OIS::KC_F10) ); + mKeyMap.insert( KeyMap::value_type(SDLK_NUMLOCKCLEAR, OIS::KC_NUMLOCK) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SCROLLLOCK, OIS::KC_SCROLL)); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_7, OIS::KC_NUMPAD7) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_8, OIS::KC_NUMPAD8) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_9, OIS::KC_NUMPAD9) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_MINUS, OIS::KC_SUBTRACT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_4, OIS::KC_NUMPAD4) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_5, OIS::KC_NUMPAD5) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_6, OIS::KC_NUMPAD6) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_PLUS, OIS::KC_ADD) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_1, OIS::KC_NUMPAD1) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_2, OIS::KC_NUMPAD2) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_3, OIS::KC_NUMPAD3) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_0, OIS::KC_NUMPAD0) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_PERIOD, OIS::KC_DECIMAL) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F11, OIS::KC_F11) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F12, OIS::KC_F12) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F13, OIS::KC_F13) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F14, OIS::KC_F14) ); + mKeyMap.insert( KeyMap::value_type(SDLK_F15, OIS::KC_F15) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_EQUALS, OIS::KC_NUMPADEQUALS) ); + mKeyMap.insert( KeyMap::value_type(SDLK_KP_DIVIDE, OIS::KC_DIVIDE) ); + mKeyMap.insert( KeyMap::value_type(SDLK_SYSREQ, OIS::KC_SYSRQ) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RALT, OIS::KC_RMENU) ); + mKeyMap.insert( KeyMap::value_type(SDLK_HOME, OIS::KC_HOME) ); + mKeyMap.insert( KeyMap::value_type(SDLK_UP, OIS::KC_UP) ); + mKeyMap.insert( KeyMap::value_type(SDLK_PAGEUP, OIS::KC_PGUP) ); + mKeyMap.insert( KeyMap::value_type(SDLK_LEFT, OIS::KC_LEFT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_RIGHT, OIS::KC_RIGHT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_END, OIS::KC_END) ); + mKeyMap.insert( KeyMap::value_type(SDLK_DOWN, OIS::KC_DOWN) ); + mKeyMap.insert( KeyMap::value_type(SDLK_PAGEDOWN, OIS::KC_PGDOWN) ); + mKeyMap.insert( KeyMap::value_type(SDLK_INSERT, OIS::KC_INSERT) ); + mKeyMap.insert( KeyMap::value_type(SDLK_DELETE, OIS::KC_DELETE) ); + } +} diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp new file mode 100644 index 0000000000..63b4c922b8 --- /dev/null +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -0,0 +1,67 @@ +#ifndef _MWINPUT_SDLINPUTWRAPPER_H +#define _MWINPUT_SDLINPUTWRAPPER_H + +#include "SDL2/SDL_events.h" +#include +#include + +#include "OISCompat.h" +#include "events.h" + + +namespace SFO +{ + class InputWrapper + { + public: + InputWrapper(Ogre::RenderWindow* window); + ~InputWrapper(); + + void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } + void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } + void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } + + void capture(); + bool isModifierHeld(int mod); + + void setMouseRelative(bool relative); + bool getMouseRelative() { return mMouseRelative; } + void setGrabPointer(bool grab); + + OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); + + void warpMouse(int x, int y); + private: + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); + void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + + MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); + void _handleKeyPress(SDL_KeyboardEvent& evt); + + bool _start(); + void _setupOISKeys(); + + SFO::MouseListener* mMouseListener; + SFO::KeyListener* mKeyboardListener; + SFO::WindowListener* mWindowListener; + + typedef boost::unordered::unordered_map KeyMap; + KeyMap mKeyMap; + + Uint16 mWarpX; + Uint16 mWarpY; + bool mWarpCompensate; + bool mMouseRelative; + bool mWrapPointer; + bool mGrabPointer; + + Sint32 mMouseZ; + Sint32 mMouseX; + Sint32 mMouseY; + + Ogre::RenderWindow* mWindow; + SDL_Window* mSDLWindow; + }; +} + +#endif From 601d79ef3f83d741d1913911845863037000690b Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 17:59:49 -0400 Subject: [PATCH 0010/1537] fix the mouse wheel in mygui --- apps/openmw/mwinput/inputmanagerimp.cpp | 3 +-- extern/sdl4ogre/sdlinputwrapper.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6d25f7dc66..308065e7e1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -487,8 +487,7 @@ namespace MWInput mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); - //there's no such thing as an absolute z position, so let's keep track of it ourselves - mMouseWheel += arg.zrel; + mMouseWheel = int(arg.z); MyGUI::InputManager::getInstance().injectMouseMove( int(mMouseX), int(mMouseY), mMouseWheel); } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index b7d1550c90..93f00d4b5e 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -288,7 +288,7 @@ namespace SFO } else if(evt.type == SDL_MOUSEWHEEL) { - mMouseZ += pack_evt.zrel = evt.wheel.y; + mMouseZ += pack_evt.zrel = (evt.wheel.y * 120); pack_evt.z = mMouseZ; } else From 403b6756f516cb700c2f033890947070b29892c9 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 23:29:51 -0400 Subject: [PATCH 0011/1537] remove dependency on boost::locale, use system mouse position in in-game menus --- apps/openmw/mwinput/inputmanagerimp.cpp | 21 ++--- extern/sdl4ogre/sdlinputwrapper.cpp | 105 +++++++++++++++++------- extern/sdl4ogre/sdlinputwrapper.hpp | 7 +- 3 files changed, 86 insertions(+), 47 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 308065e7e1..358eb7b928 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -221,9 +221,10 @@ namespace MWInput bool main_menu = mWindows.containsMode(MWGui::GM_MainMenu); bool was_relative = mInputManager->getMouseRelative(); - bool is_relative = !main_menu; + bool is_relative = !mWindows.isGuiMode(); - //don't keep the pointer away from the window edge in the main menu + // don't keep the pointer away from the window edge in gui mode + // stop using raw mouse motions and switch to system cursor movements mInputManager->setMouseRelative(is_relative); //we switched to non-relative mode, move our cursor to where the in-game @@ -472,17 +473,11 @@ namespace MWInput // We keep track of our own mouse position, so that moving the mouse while in // game mode does not move the position of the GUI cursor - //FIXME: Except in the main menu, since we let the pointer escape - if(!mWindows.containsMode(MWGui::GM_MainMenu)) - { - mMouseX += float(arg.xrel) * mUISensitivity; - mMouseY += float(arg.yrel) * mUISensitivity * mUIYMultiplier; - } - else - { - mMouseX = arg.x; - mMouseY = arg.y; - } + // Don't support the UI sensitivity slider to reduce headache + // related to when the mouse can leave the window, and what to + // do when it re-enters + mMouseX = arg.x; + mMouseY = arg.y; mMouseX = std::max(0.f, std::min(mMouseX, float(viewSize.width))); mMouseY = std::max(0.f, std::min(mMouseY, float(viewSize.height))); diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 93f00d4b5e..a198542c7a 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -3,7 +3,6 @@ #include #include -#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -239,36 +238,6 @@ namespace SFO } } - void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) - { - //SDL keyboard events are followed by the actual text those keys would generate - //to account for languages that require multiple keystrokes to produce a key. - //Look for an event immediately following ours, assuming each key produces exactly - //one character or none at all. - - //TODO: Check if this works properly for multibyte symbols - //do we have to worry about endian-ness? - //for that matter, check if we even need to do any of this. - - SDL_Event text_evts[1]; - if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) - { - const char* symbol = text_evts[0].text.text; - - Uint32 num_bytes = strlen(symbol); - - //no valid character is more than 4 bytes - if(num_bytes > 0 && num_bytes <= 4) - { - Uint32 u32_symbol = boost::locale::conv::utf_to_utf(symbol)[0]; - - evt.keysym.unicode = u32_symbol; - } - } - - mKeyboardListener->keyPressed(evt); - } - MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) { MouseMotionEvent pack_evt; @@ -299,6 +268,74 @@ namespace SFO return pack_evt; } + void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) + { + //SDL keyboard events are followed by the actual text those keys would generate + //to account for languages that require multiple keystrokes to produce a key. + //Look for an event immediately following ours, assuming each key produces exactly + //one character or none at all. + + //TODO: Check if this works properly for multibyte symbols + //do we have to worry about endian-ness? + //for that matter, check if we even need to do any of this. + + SDL_Event text_evts[1]; + if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) + { + if(strlen(text_evts[0].text.text) != 0) + { + const unsigned char* symbol = reinterpret_cast(&(text_evts[0].text.text[0])); + evt.keysym.unicode = _UTF8ToUTF32(symbol); + } + } + + mKeyboardListener->keyPressed(evt); + } + + //Lifted from OIS' LinuxKeyboard.cpp + Uint32 InputWrapper::_UTF8ToUTF32(const unsigned char *buf) + { + unsigned char FirstChar = buf[0]; + + //it's an ascii char, bail out early. + if(FirstChar < 128) + return FirstChar; + + Uint32 val = 0; + Sint32 len = 0; + + if((FirstChar & 0xE0) == 0xC0) //2 Chars + { + len = 2; + val = FirstChar & 0x1F; + } + else if((FirstChar & 0xF0) == 0xE0) //3 Chars + { + len = 3; + val = FirstChar & 0x0F; + } + else if((FirstChar & 0xF8) == 0xF0) //4 Chars + { + len = 4; + val = FirstChar & 0x07; + } + else if((FirstChar & 0xFC) == 0xF8) //5 Chars + { + len = 5; + val = FirstChar & 0x03; + } + else // if((FirstChar & 0xFE) == 0xFC) //6 Chars + { + len = 6; + val = FirstChar & 0x01; + } + + for(int i = 1; i < len; i++) + val = (val << 6) | (buf[i] & 0x3F); + + return val; + } + OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code) { OIS::KeyCode kc = OIS::KC_UNASSIGNED; @@ -307,6 +344,8 @@ namespace SFO if(ois_equiv != mKeyMap.end()) kc = ois_equiv->second; + else + std::cerr << "Couldn't find OIS key for " << SDLK_SYSREQ << std::endl; return kc; } @@ -314,6 +353,10 @@ namespace SFO void InputWrapper::_setupOISKeys() { //lifted from OIS's SDLKeyboard.cpp + + //TODO: Consider switching to scancodes so we + //can properly support international keyboards + //look at SDL_GetKeyFromScancode and SDL_GetKeyName mKeyMap.insert( KeyMap::value_type(SDLK_UNKNOWN, OIS::KC_UNASSIGNED)); mKeyMap.insert( KeyMap::value_type(SDLK_ESCAPE, OIS::KC_ESCAPE) ); mKeyMap.insert( KeyMap::value_type(SDLK_1, OIS::KC_1) ); diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 63b4c922b8..55c45316fc 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -32,13 +32,14 @@ namespace SFO void warpMouse(int x, int y); private: + bool _start(); + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); - MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); - void _handleKeyPress(SDL_KeyboardEvent& evt); - bool _start(); + void _handleKeyPress(SDL_KeyboardEvent& evt); + Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); SFO::MouseListener* mMouseListener; From a030c035133d4fcbad08272bb33997adfd45580c Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Thu, 10 Jan 2013 23:53:19 -0400 Subject: [PATCH 0012/1537] support the printscreen button properly --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- extern/oics/ICSInputControlSystem.cpp | 1 + extern/sdl4ogre/sdlinputwrapper.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 358eb7b928..7785167f83 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -716,7 +716,7 @@ namespace MWInput defaultKeyBindings[A_QuickKey8] = SDLK_8; defaultKeyBindings[A_QuickKey9] = SDLK_9; defaultKeyBindings[A_QuickKey10] = SDLK_0; - defaultKeyBindings[A_Screenshot] = SDLK_SYSREQ; + defaultKeyBindings[A_Screenshot] = SDLK_PRINTSCREEN; defaultKeyBindings[A_ToggleHUD] = SDLK_F12; std::map defaultMouseButtonBindings; diff --git a/extern/oics/ICSInputControlSystem.cpp b/extern/oics/ICSInputControlSystem.cpp index 159b3241ff..cdf8fbfe2f 100644 --- a/extern/oics/ICSInputControlSystem.cpp +++ b/extern/oics/ICSInputControlSystem.cpp @@ -892,6 +892,7 @@ namespace ICS mKeys["RCONTROL"]= SDLK_RCTRL; mKeys["DIVIDE"]= SDLK_SLASH; mKeys["SYSRQ"]= SDLK_SYSREQ; + mKeys["PRNTSCRN"] = SDLK_PRINTSCREEN; mKeys["RMENU"]= SDLK_RALT; mKeys["PAUSE"]= SDLK_PAUSE; mKeys["HOME"]= SDLK_HOME; diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index a198542c7a..e194719cbf 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -345,7 +345,7 @@ namespace SFO if(ois_equiv != mKeyMap.end()) kc = ois_equiv->second; else - std::cerr << "Couldn't find OIS key for " << SDLK_SYSREQ << std::endl; + std::cerr << "Couldn't find OIS key for " << code << std::endl; return kc; } From 1117105039768175d517a758f216ad1cb0d8c992 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 00:37:04 -0400 Subject: [PATCH 0013/1537] fix compile error with boost includes --- extern/sdl4ogre/sdlinputwrapper.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 55c45316fc..eba2ed8d06 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -46,7 +46,7 @@ namespace SFO SFO::KeyListener* mKeyboardListener; SFO::WindowListener* mWindowListener; - typedef boost::unordered::unordered_map KeyMap; + typedef boost::unordered_map KeyMap; KeyMap mKeyMap; Uint16 mWarpX; From f9b064d1bc17699558b2298eb35ed271cf43b8e6 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 08:27:59 -0400 Subject: [PATCH 0014/1537] add preliminary hardware cursor support into sdl4ogre and windowmanagerimp, handle alt-tabbing away from fullscreen gracefully --- apps/openmw/mwbase/windowmanager.hpp | 7 ++ apps/openmw/mwgui/cursorreplace.cpp | 64 +++++++++++ apps/openmw/mwgui/cursorreplace.hpp | 35 +++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 51 +++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 11 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 2 + extern/sdl4ogre/sdlinputwrapper.cpp | 134 +++++++++++++++++++++++- extern/sdl4ogre/sdlinputwrapper.hpp | 35 ++++++- 8 files changed, 334 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 13a35b5926..e7a63a1b50 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -55,6 +55,11 @@ namespace MWGui class DialogueWindow; } +namespace SFO +{ + class CursorChangeClient; +} + namespace MWBase { /// \brief Interface for widnow manager (implemented in MWGui) @@ -238,6 +243,8 @@ namespace MWBase virtual void startTraining(MWWorld::Ptr actor) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual void setCursorChangeClient(SFO::CursorChangeClient* client) = 0; }; } diff --git a/apps/openmw/mwgui/cursorreplace.cpp b/apps/openmw/mwgui/cursorreplace.cpp index 2079538fc2..f883a4ed7e 100644 --- a/apps/openmw/mwgui/cursorreplace.cpp +++ b/apps/openmw/mwgui/cursorreplace.cpp @@ -5,9 +5,73 @@ #include #include +#include using namespace MWGui; + +#include "MyGUI_Precompiled.h" +#include "MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_ImageBox.h" +#include "MyGUI_ResourceManager.h" + + + + ResourceImageSetPointerFix::ResourceImageSetPointerFix() : + mImageSet(nullptr) + { + } + + ResourceImageSetPointerFix::~ResourceImageSetPointerFix() + { + } + + void ResourceImageSetPointerFix::deserialization(xml::ElementPtr _node, Version _version) + { + Base::deserialization(_node, _version); + + // берем детей и крутимся, основной цикл + xml::ElementEnumerator info = _node->getElementEnumerator(); + while (info.next("Property")) + { + const std::string& key = info->findAttribute("key"); + const std::string& value = info->findAttribute("value"); + + if (key == "Point") + mPoint = IntPoint::parse(value); + else if (key == "Size") + mSize = IntSize::parse(value); + else if (key == "Resource") + mImageSet = ResourceManager::getInstance().getByName(value)->castType(); + } + } + + void ResourceImageSetPointerFix::setImage(ImageBox* _image) + { + if (mImageSet != nullptr) + _image->setItemResourceInfo(mImageSet->getIndexInfo(0, 0)); + } + + void ResourceImageSetPointerFix::setPosition(ImageBox* _image, const IntPoint& _point) + { + _image->setCoord(_point.left - mPoint.left, _point.top - mPoint.top, mSize.width, mSize.height); + } + + ResourceImageSetPtr ResourceImageSetPointerFix:: getImageSet() + { + return mImageSet; + } + + IntPoint ResourceImageSetPointerFix::getHotSpot() + { + return mPoint; + } + + IntSize ResourceImageSetPointerFix::getSize() + { + return mSize; + } + CursorReplace::CursorReplace() { OEngine::Render::ImageRotate::rotate("textures\\tx_cursormove.dds", "mwpointer_vresize.png", 90); diff --git a/apps/openmw/mwgui/cursorreplace.hpp b/apps/openmw/mwgui/cursorreplace.hpp index 06fe28e39a..402eda1abd 100644 --- a/apps/openmw/mwgui/cursorreplace.hpp +++ b/apps/openmw/mwgui/cursorreplace.hpp @@ -2,9 +2,44 @@ #define GAME_CURSORREPLACE_H #include +#include +#include + +using namespace MyGUI; namespace MWGui { + /// \brief A simple class that allows us to get the members of + /// ResourceImageSetPointer that we need. Use with + /// MyGUI + /// \example MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + /// MyGUI::ResourceManager::getInstance().load("core.xml"); + class ResourceImageSetPointerFix : + public IPointer + { + MYGUI_RTTI_DERIVED( ResourceImageSetPointerFix ) + + public: + ResourceImageSetPointerFix(); + virtual ~ResourceImageSetPointerFix(); + + virtual void deserialization(xml::ElementPtr _node, Version _version); + + virtual void setImage(ImageBox* _image); + virtual void setPosition(ImageBox* _image, const IntPoint& _point); + + //and now for the whole point of this class, allow us to get + //the hot spot, the image and the size of the cursor. + virtual ResourceImageSetPtr getImageSet(); + virtual IntPoint getHotSpot(); + virtual IntSize getSize(); + + private: + IntPoint mPoint; + IntSize mSize; + ResourceImageSetPtr mImageSet; + }; + /// \brief MyGUI does not support rotating cursors, so we have to do it manually class CursorReplace { diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index d653b578ad..7c99d004ed 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -4,10 +4,15 @@ #include #include "MyGUI_UString.h" +#include "MYGUI/MyGUI_IPointer.h" +#include "MYGUI/MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_TextureUtility.h" #include #include +#include + #include #include @@ -53,6 +58,8 @@ #include "trainingwindow.hpp" #include "imagebutton.hpp" +#include "cursorreplace.hpp" + using namespace MWGui; WindowManager::WindowManager( @@ -108,12 +115,17 @@ WindowManager::WindowManager( , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) + , mCursorChangeClient(NULL) { // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); mGui = mGuiManager->getGui(); + //Use our own ResourceImageSetPointer class so we can get the texture and hotspot for a pointer + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -130,6 +142,7 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); + MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); // Get size info from the Gui object assert(mGui); @@ -758,6 +771,44 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r } } + void WindowManager::setCursorChangeClient(SFO::CursorChangeClient* client) + { + mCursorChangeClient = client; + onCursorChange(PointerManager::getInstance().getDefaultPointer()); + } + +void WindowManager::onCursorChange(const std::string &name) +{ + //we have no client, don't care. + if(!mCursorChangeClient) + return; + + //the client doesn't want any more info about this cursor + if(!mCursorChangeClient->cursorChanged(name)) + return; + //See if we can get the information we need out of the cursor resource + ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); + if(imgSetPtr != NULL) + { + MyGUI::ResourceImageSet* imgSet = imgSetPtr->getImageSet(); + + std::string tex_name = imgSet->getIndexInfo(0,0).texture; + + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(tex_name); + + //everything looks good, send it to the client + if(!tex.isNull()) + { + Uint8 size_x = imgSetPtr->getSize().width; + Uint8 size_y = imgSetPtr->getSize().height; + Uint8 hotspot_x = imgSetPtr->getHotSpot().left; + Uint8 hotspot_y = imgSetPtr->getHotSpot().top; + + mCursorChangeClient->receiveCursorInfo(name, tex, size_x, size_y, hotspot_x, hotspot_y); + } + } +} + void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) { mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e2a9666607..bbcdbbb416 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -48,6 +48,11 @@ namespace OEngine } } +namespace SFO +{ + class CursorChangeClient; +} + namespace MWGui { class WindowBase; @@ -228,6 +233,8 @@ namespace MWGui virtual const Translation::Storage& getTranslationDataStorage() const; + virtual void setCursorChangeClient(SFO::CursorChangeClient* client); + private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; @@ -282,6 +289,8 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; + SFO::CursorChangeClient* mCursorChangeClient; + std::vector mGarbageDialogs; void cleanupGarbage(); @@ -310,6 +319,8 @@ namespace MWGui * 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); + + void onCursorChange(const std::string& name); }; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 7785167f83..c1f857b5f0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -67,6 +67,8 @@ namespace MWInput mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); + mWindows.setCursorChangeClient(mInputManager); + std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index e194719cbf..1b996ce064 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -13,6 +15,8 @@ namespace SFO { + /// \brief General purpose wrapper for OGRE applications around SDL's event + /// queue, mostly used for handling input-related events. InputWrapper::InputWrapper(Ogre::RenderWindow *window) : mWindow(window), mSDLWindow(NULL), @@ -58,6 +62,11 @@ namespace SFO if(mSDLWindow == NULL) return false; + //without this SDL will take ownership of the window and iconify it when + //we alt-tab away. + SDL_SetWindowFullscreen(mSDLWindow, 0); + + //translate our keypresses into text SDL_StartTextInput(); #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX @@ -160,6 +169,7 @@ namespace SFO return SDL_GetModState() & mod; } + /// \brief Moves the mouse to the specified point within the viewport void InputWrapper::warpMouse(int x, int y) { SDL_WarpMouseInWindow(mSDLWindow, x, y); @@ -168,14 +178,15 @@ namespace SFO mWarpY = y; } + /// \brief Locks the pointer to the window void InputWrapper::setGrabPointer(bool grab) { - SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; - mGrabPointer = grab; - SDL_SetWindowGrab(mSDLWindow, sdlGrab); + SDL_SetWindowGrab(mSDLWindow, grab ? SDL_TRUE : SDL_FALSE); } + /// \brief Set the mouse to relative positioning. Doesn't move the cursor + /// and disables mouse acceleration. void InputWrapper::setMouseRelative(bool relative) { if(mMouseRelative == relative) @@ -200,6 +211,121 @@ namespace SFO SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); } + bool InputWrapper::cursorChanged(const std::string &name) + { + CursorMap::const_iterator curs_iter = mCursorMap.find(name); + + //we have this cursor + if(curs_iter != mCursorMap.end()) + { + SDL_SetCursor(curs_iter->second); + return false; + } + else + { + //they should get back to use with more info + return true; + } + } + + void InputWrapper::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); + } + + /// \brief creates an SDL cursor from an Ogre texture + void InputWrapper::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + Ogre::Image::Box box; + box.right = size_x; + box.bottom = size_y; + + //get the surfaces set up + Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); + buffer.get()->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY); + + std::string tempName = "_" + name + "_processing"; + + //we need to copy this to a temporary texture since Ogre doesn't like us using getColourAt + Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( + tempName, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + size_x, size_y, + 0, + Ogre::PF_FLOAT16_RGBA, + Ogre::TU_STATIC); + + tempTexture->getBuffer()->blit(buffer); + buffer->unlock(); + + Ogre::HardwarePixelBufferSharedPtr new_buffer = tempTexture.get()->getBuffer(); + //FIXME: Casting away constness is almost certainly the wrong thing to do here + Ogre::PixelBox& pixels = const_cast(new_buffer->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY)); + + + SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0,0,0,0); + + + //copy the Ogre texture to an SDL surface + for(size_t x = 0; x < size_x; ++x) + { + for(size_t y = 0; y < size_y; ++y) + { + Ogre::ColourValue clr = pixels.getColourAt(x, y, 0); + + //set the pixel on the SDL surface to the same value as the Ogre texture's + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r, clr.g, clr.b, clr.a)); + } + } + + //set the cursor and store it for later + SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); + SDL_SetCursor(curs); + mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); + + new_buffer->unlock(); + + //clean up + SDL_FreeSurface(surf); + Ogre::TextureManager::getSingleton().remove(tempName); + } + + void InputWrapper::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) + { + int bpp = surface->format->BytesPerPixel; + /* Here p is the address to the pixel we want to set */ + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + + switch(bpp) { + case 1: + *p = pixel; + break; + + case 2: + *(Uint16 *)p = pixel; + break; + + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (pixel >> 16) & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = pixel & 0xff; + } else { + p[0] = pixel & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = (pixel >> 16) & 0xff; + } + break; + + case 4: + *(Uint32 *)p = pixel; + break; + } + } + + /// \brief Internal method for ignoring relative motions as a side effect + /// of warpMouse() bool InputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) { if(!mWarpCompensate) @@ -215,6 +341,7 @@ namespace SFO return false; } + /// \brief Wrap the mouse to the viewport void InputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) { //don't wrap if we don't want relative movements, support relative @@ -238,6 +365,7 @@ namespace SFO } } + /// \brief Package mouse and mousewheel motions into a single event MouseMotionEvent InputWrapper::_packageMouseMotion(const SDL_Event &evt) { MouseMotionEvent pack_evt; diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index eba2ed8d06..aac2bf5665 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -9,13 +9,33 @@ #include "events.h" +namespace Ogre +{ + class Texture; +} + namespace SFO { - class InputWrapper + + + class CursorChangeClient + { + public: + /// \brief Tell the client that the cursor has changed, giving the + /// name of the cursor we changed to ("arrow", "ibeam", etc) + /// \return Whether the client is interested in more information about the cursor + virtual bool cursorChanged(const std::string &name) = 0; + + /// \brief Follow up a cursorChanged() call with enough info to create an SDL cursor. + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; + }; + + class InputWrapper : + public CursorChangeClient { public: InputWrapper(Ogre::RenderWindow* window); - ~InputWrapper(); + virtual ~InputWrapper(); void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } @@ -28,9 +48,13 @@ namespace SFO bool getMouseRelative() { return mMouseRelative; } void setGrabPointer(bool grab); + virtual bool cursorChanged(const std::string &name); + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); void warpMouse(int x, int y); + private: bool _start(); @@ -38,6 +62,9 @@ namespace SFO void _wrapMousePointer(const SDL_MouseMotionEvent &evt); MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); + void _createCursorFromResource(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + void _handleKeyPress(SDL_KeyboardEvent& evt); Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); @@ -49,6 +76,9 @@ namespace SFO typedef boost::unordered_map KeyMap; KeyMap mKeyMap; + typedef std::map CursorMap; + CursorMap mCursorMap; + Uint16 mWarpX; Uint16 mWarpY; bool mWarpCompensate; @@ -63,6 +93,7 @@ namespace SFO Ogre::RenderWindow* mWindow; SDL_Window* mSDLWindow; }; + } #endif From eeacb04fe24e4d21f91c407e839c662a8f41a83d Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 09:32:29 -0400 Subject: [PATCH 0015/1537] Fully working hardware cursors (if you compile SDL2 with XCursor support) --- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 22 ++++++++++++++++------ apps/openmw/mwgui/windowmanagerimp.hpp | 3 ++- extern/sdl4ogre/sdlinputwrapper.cpp | 9 +++++++-- extern/sdl4ogre/sdlinputwrapper.hpp | 4 ++++ 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index e7a63a1b50..c7dc06472c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -159,7 +159,7 @@ namespace MWBase virtual void setFocusObject(const MWWorld::Ptr& focus) = 0; virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) = 0; - virtual void setMouseVisible(bool visible) = 0; + virtual void setCursorVisible(bool visible) = 0; virtual void getMousePosition(int &x, int &y) = 0; virtual void getMousePosition(float &x, float &y) = 0; virtual void setDragDrop(bool dragDrop) = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7c99d004ed..781f3c86c1 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -190,6 +190,9 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + //make sure the cursor in the GL context isn't visible + MyGUI::PointerManager::getInstance().setVisible(false); + // The HUD is always on mHud->setVisible(true); @@ -302,7 +305,7 @@ void WindowManager::updateVisible() mHud->setVisible(true); // Mouse is visible whenever we're not in game mode - MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); + setCursorVisible(isGuiMode()); bool gameMode = !isGuiMode(); @@ -417,13 +420,13 @@ void WindowManager::updateVisible() break; case GM_LoadingWallpaper: mHud->setVisible(false); - MyGUI::PointerManager::getInstance().setVisible(false); + setCursorVisible(false); break; case GM_Loading: - MyGUI::PointerManager::getInstance().setVisible(false); + setCursorVisible(false); break; case GM_Video: - MyGUI::PointerManager::getInstance().setVisible(false); + setCursorVisible(false); mHud->setVisible(false); break; default: @@ -737,9 +740,15 @@ void WindowManager::setSpellVisibility(bool visible) mHud->setEffectVisible (visible); } -void WindowManager::setMouseVisible(bool visible) +void WindowManager::setCursorVisible(bool visible) { - MyGUI::PointerManager::getInstance().setVisible(visible); + if(visible == mCursorVisible) + return; + + mCursorVisible = visible; + + if(mCursorChangeClient != NULL) + mCursorChangeClient->cursorVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) @@ -775,6 +784,7 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r { mCursorChangeClient = client; onCursorChange(PointerManager::getInstance().getDefaultPointer()); + client->cursorVisible(mCursorVisible); } void WindowManager::onCursorChange(const std::string &name) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index bbcdbbb416..4334de83fb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -154,7 +154,7 @@ namespace MWGui virtual void setFocusObject(const MWWorld::Ptr& focus); virtual void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); - virtual void setMouseVisible(bool visible); + virtual void setCursorVisible(bool visible); virtual void getMousePosition(int &x, int &y); virtual void getMousePosition(float &x, float &y); virtual void setDragDrop(bool dragDrop); @@ -275,6 +275,7 @@ namespace MWGui bool mCrosshairEnabled; bool mSubtitlesEnabled; bool mHudEnabled; + bool mCursorVisible; /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. // Various stats about player as needed by window manager diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 1b996ce064..c996924e47 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -228,6 +228,11 @@ namespace SFO } } + void InputWrapper::cursorVisible(bool visible) + { + SDL_ShowCursor(visible ? SDL_TRUE : SDL_FALSE); + } + void InputWrapper::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); @@ -264,7 +269,7 @@ namespace SFO Ogre::PixelBox& pixels = const_cast(new_buffer->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY)); - SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0,0,0,0); + SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); //copy the Ogre texture to an SDL surface @@ -275,7 +280,7 @@ namespace SFO Ogre::ColourValue clr = pixels.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r, clr.g, clr.b, clr.a)); + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); } } diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index aac2bf5665..d37a43e339 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -28,6 +28,9 @@ namespace SFO /// \brief Follow up a cursorChanged() call with enough info to create an SDL cursor. virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; + + /// \brief Tell the client when the cursor visibility changed + virtual void cursorVisible(bool visible) = 0; }; class InputWrapper : @@ -50,6 +53,7 @@ namespace SFO virtual bool cursorChanged(const std::string &name); virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void cursorVisible(bool visible); OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); From 651a654985a50820bed817f4374cbbc83a842afa Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 11 Jan 2013 10:09:26 -0400 Subject: [PATCH 0016/1537] clean up our cursors during destruction --- extern/sdl4ogre/sdlinputwrapper.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index c996924e47..190612fd8c 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -37,6 +37,17 @@ namespace SFO if(mSDLWindow != NULL) SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; + + CursorMap::const_iterator curs_iter = mCursorMap.begin(); + + while(curs_iter != mCursorMap.end()) + { + SDL_FreeCursor(curs_iter->second); + ++curs_iter; + } + + mCursorMap.clear(); + SDL_StopTextInput(); SDL_Quit(); } From d71b58385536589e58b16bb8d2f8d3c1cac6a9cb Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 11 Jan 2013 22:25:34 +0100 Subject: [PATCH 0017/1537] fix const cast, fix comment --- extern/sdl4ogre/sdlinputwrapper.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 190612fd8c..b6761e883e 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -252,17 +252,14 @@ namespace SFO /// \brief creates an SDL cursor from an Ogre texture void InputWrapper::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) { - Ogre::Image::Box box; - box.right = size_x; - box.bottom = size_y; - //get the surfaces set up Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); - buffer.get()->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY); + buffer.get()->lock(Ogre::HardwarePixelBuffer::HBL_READ_ONLY); std::string tempName = "_" + name + "_processing"; - //we need to copy this to a temporary texture since Ogre doesn't like us using getColourAt + //we need to copy this to a temporary texture first because the cursors might be in DDS format, + //and Ogre doesn't have an interface to read DDS Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( tempName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, @@ -275,10 +272,9 @@ namespace SFO tempTexture->getBuffer()->blit(buffer); buffer->unlock(); - Ogre::HardwarePixelBufferSharedPtr new_buffer = tempTexture.get()->getBuffer(); - //FIXME: Casting away constness is almost certainly the wrong thing to do here - Ogre::PixelBox& pixels = const_cast(new_buffer->lock(box, Ogre::HardwarePixelBuffer::HBL_READ_ONLY)); - + // now blit to memory + Ogre::Image destImage; + tempTexture->convertToImage(destImage); SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); @@ -288,7 +284,7 @@ namespace SFO { for(size_t y = 0; y < size_y; ++y) { - Ogre::ColourValue clr = pixels.getColourAt(x, y, 0); + Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); //set the pixel on the SDL surface to the same value as the Ogre texture's _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); @@ -300,8 +296,6 @@ namespace SFO SDL_SetCursor(curs); mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); - new_buffer->unlock(); - //clean up SDL_FreeSurface(surf); Ogre::TextureManager::getSingleton().remove(tempName); From 5a6589af0155b058fc63c095f38c8568c59f6c77 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 11:57:29 -0400 Subject: [PATCH 0018/1537] extract cursor management to a separate class, have windowmanager communicate with it. Initialize SDL during engine start --- apps/openmw/engine.cpp | 15 ++ apps/openmw/mwbase/windowmanager.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 57 +++--- apps/openmw/mwgui/windowmanagerimp.hpp | 9 +- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +- extern/sdl4ogre/CMakeLists.txt | 8 +- extern/sdl4ogre/cursormanager.hpp | 35 ++++ extern/sdl4ogre/sdlcursormanager.cpp | 189 ++++++++++++++++++++ extern/sdl4ogre/sdlcursormanager.hpp | 44 +++++ extern/sdl4ogre/sdlinputwrapper.cpp | 220 +++++------------------- extern/sdl4ogre/sdlinputwrapper.hpp | 41 +---- 11 files changed, 382 insertions(+), 249 deletions(-) create mode 100644 extern/sdl4ogre/cursormanager.hpp create mode 100644 extern/sdl4ogre/sdlcursormanager.cpp create mode 100644 extern/sdl4ogre/sdlcursormanager.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 4413e98f46..51dbabba51 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -36,6 +36,8 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" +#include "SDL2/SDL.h" + void OMW::Engine::executeLocalScripts() { @@ -272,6 +274,9 @@ std::string OMW::Engine::loadSettings (Settings::Manager & settings) else if (boost::filesystem::exists(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg")) nifOverrides.loadTransparencyOverrides(mCfgMgr.getGlobalPath().string() + "/transparency-overrides.cfg"); + settings.setBool("hardware cursors", "GUI", true); + settings.setBool("debug", "Engine", mDebug); + return settingspath; } @@ -322,6 +327,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) loadBSA(); + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + if(SDL_WasInit(flags) == 0) + { + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(flags) != 0) + throw std::runtime_error("Couldn't initialize SDL!"); + } + // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c7dc06472c..06b1df7b9a 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -57,7 +57,7 @@ namespace MWGui namespace SFO { - class CursorChangeClient; + class CursorManager; } namespace MWBase @@ -243,8 +243,6 @@ namespace MWBase virtual void startTraining(MWWorld::Ptr actor) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; - - virtual void setCursorChangeClient(SFO::CursorChangeClient* client) = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 781f3c86c1..20301b1b22 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include @@ -115,7 +115,8 @@ WindowManager::WindowManager( , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) , mHudEnabled(true) , mTranslationDataStorage (translationDataStorage) - , mCursorChangeClient(NULL) + , mCursorManager(NULL) + , mUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")) { // Set up the GUI system @@ -190,9 +191,6 @@ WindowManager::WindowManager( mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - //make sure the cursor in the GL context isn't visible - MyGUI::PointerManager::getInstance().setVisible(false); - // The HUD is always on mHud->setVisible(true); @@ -212,6 +210,13 @@ WindowManager::WindowManager( unsetSelectedSpell(); unsetSelectedWeapon(); + //set up the hardware cursor manager + mCursorManager = new SFO::SDLCursorManager(Settings::Manager::getBool("debug", "Engine")); + + setUseHardwareCursors(mUseHardwareCursors); + onCursorChange(PointerManager::getInstance().getDefaultPointer()); + mCursorManager->cursorVisibilityChange(false); + // Set up visibility updateVisible(); } @@ -252,6 +257,7 @@ WindowManager::~WindowManager() cleanupGarbage(); delete mGuiManager; + delete mCursorManager; } void WindowManager::cleanupGarbage() @@ -740,15 +746,30 @@ void WindowManager::setSpellVisibility(bool visible) mHud->setEffectVisible (visible); } +void WindowManager::setUseHardwareCursors(bool use) +{ + mCursorManager->setEnabled(use); + + if(!use) + { + MyGUI::PointerManager::getInstance().setVisible(false); + } + else + { + MyGUI::PointerManager::getInstance().setVisible(mCursorVisible); + } +} + void WindowManager::setCursorVisible(bool visible) { - if(visible == mCursorVisible) + if(mCursorVisible == visible) return; mCursorVisible = visible; + mCursorManager->cursorVisibilityChange(visible); - if(mCursorChangeClient != NULL) - mCursorChangeClient->cursorVisible(visible); + if(!mUseHardwareCursors) + MyGUI::PointerManager::getInstance().setVisible(visible); } void WindowManager::setDragDrop(bool dragDrop) @@ -780,21 +801,10 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r } } - void WindowManager::setCursorChangeClient(SFO::CursorChangeClient* client) - { - mCursorChangeClient = client; - onCursorChange(PointerManager::getInstance().getDefaultPointer()); - client->cursorVisible(mCursorVisible); - } - void WindowManager::onCursorChange(const std::string &name) { - //we have no client, don't care. - if(!mCursorChangeClient) - return; - - //the client doesn't want any more info about this cursor - if(!mCursorChangeClient->cursorChanged(name)) + //the cursor manager doesn't want any more info about this cursor + if(!mCursorManager->cursorChanged(name)) return; //See if we can get the information we need out of the cursor resource ResourceImageSetPointerFix* imgSetPtr = dynamic_cast(MyGUI::PointerManager::getInstance().getByName(name)); @@ -806,7 +816,7 @@ void WindowManager::onCursorChange(const std::string &name) Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton().getByName(tex_name); - //everything looks good, send it to the client + //everything looks good, send it to the cursor manager if(!tex.isNull()) { Uint8 size_x = imgSetPtr->getSize().width; @@ -814,7 +824,7 @@ void WindowManager::onCursorChange(const std::string &name) Uint8 hotspot_x = imgSetPtr->getHotSpot().left; Uint8 hotspot_y = imgSetPtr->getHotSpot().top; - mCursorChangeClient->receiveCursorInfo(name, tex, size_x, size_y, hotspot_x, hotspot_y); + mCursorManager->receiveCursorInfo(name, tex, size_x, size_y, hotspot_x, hotspot_y); } } } @@ -823,6 +833,7 @@ void WindowManager::processChangedSettings(const Settings::CategorySettingVector { mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); + setUseHardwareCursors(Settings::Manager::getBool("hardware cursors", "GUI")); bool changeRes = false; for (Settings::CategorySettingVector::const_iterator it = changed.begin(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4334de83fb..874de8af97 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -50,7 +50,7 @@ namespace OEngine namespace SFO { - class CursorChangeClient; + class CursorManager; } namespace MWGui @@ -233,8 +233,6 @@ namespace MWGui virtual const Translation::Storage& getTranslationDataStorage() const; - virtual void setCursorChangeClient(SFO::CursorChangeClient* client); - private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; @@ -290,7 +288,7 @@ namespace MWGui MyGUI::Gui *mGui; // Gui std::vector mGuiModes; - SFO::CursorChangeClient* mCursorChangeClient; + SFO::CursorManager* mCursorManager; std::vector mGarbageDialogs; void cleanupGarbage(); @@ -315,6 +313,9 @@ namespace MWGui void onDialogueWindowBye(); + bool mUseHardwareCursors; + void setUseHardwareCursors(bool use); + /** * 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 diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c1f857b5f0..9d80de91e4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -67,8 +68,6 @@ namespace MWInput mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); - mWindows.setCursorChangeClient(mInputManager); - std::string file = userFileExists ? userFile : ""; mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -225,6 +224,9 @@ namespace MWInput bool was_relative = mInputManager->getMouseRelative(); bool is_relative = !mWindows.isGuiMode(); + //we let the mouse escape in the main menu + mInputManager->setGrabPointer(!main_menu); + // don't keep the pointer away from the window edge in gui mode // stop using raw mouse motions and switch to system cursor movements mInputManager->setMouseRelative(is_relative); @@ -235,9 +237,6 @@ namespace MWInput { mInputManager->warpMouse(mMouseX, mMouseY); } - - //we let the mouse escape in the main menu - mInputManager->setGrabPointer(!main_menu); } // Disable movement in Gui mode diff --git a/extern/sdl4ogre/CMakeLists.txt b/extern/sdl4ogre/CMakeLists.txt index c52dd4cb43..493d1ce476 100644 --- a/extern/sdl4ogre/CMakeLists.txt +++ b/extern/sdl4ogre/CMakeLists.txt @@ -4,9 +4,15 @@ set(SDL4OGRE_LIBRARY "sdl4ogre") set(SDL4OGRE_SOURCE_FILES sdlinputwrapper.cpp + sdlcursormanager.cpp ) -add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES}) +set(SDL4OGRE_HEADER_FILES + OISCompat.h + cursormanager.hpp +) + +add_library(${SDL4OGRE_LIBRARY} STATIC ${SDL4OGRE_SOURCE_FILES} ${SDL4OGRE_HEADER_FILES}) link_directories(${CMAKE_CURRENT_BINARY_DIR}) diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp new file mode 100644 index 0000000000..938f5f4c28 --- /dev/null +++ b/extern/sdl4ogre/cursormanager.hpp @@ -0,0 +1,35 @@ +#ifndef _SDL4OGRE_CURSOR_MANAGER_H +#define _SDL4OGRE_CURSOR_MANAGER_H + +#include "SDL2/SDL_types.h" +#include + +namespace Ogre +{ + class TexturePtr; +} + +namespace SFO +{ +class CursorManager +{ +public: + virtual ~CursorManager(){} + + /// \brief Tell the manager that the cursor has changed, giving the + /// name of the cursor we changed to ("arrow", "ibeam", etc) + /// \return Whether the manager is interested in more information about the cursor + virtual bool cursorChanged(const std::string &name) = 0; + + /// \brief Follow up a cursorChanged() call with enough info to create an cursor. + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; + + /// \brief Tell the manager when the cursor visibility changed + virtual void cursorVisibilityChange(bool visible) = 0; + + /// \brief sets whether to actively manage cursors or not + virtual void setEnabled(bool enabled) = 0; +}; +} + +#endif diff --git a/extern/sdl4ogre/sdlcursormanager.cpp b/extern/sdl4ogre/sdlcursormanager.cpp new file mode 100644 index 0000000000..4e24696ea1 --- /dev/null +++ b/extern/sdl4ogre/sdlcursormanager.cpp @@ -0,0 +1,189 @@ +#include "sdlcursormanager.hpp" + +#include +#include + +namespace SFO +{ + + SDLCursorManager::SDLCursorManager(bool debug) : + mDebug(debug), + mEnabled(false), + mCursorVisible(false), + mInitialized(false) + { + } + + SDLCursorManager::~SDLCursorManager() + { + CursorMap::const_iterator curs_iter = mCursorMap.begin(); + + while(curs_iter != mCursorMap.end()) + { + SDL_FreeCursor(curs_iter->second); + ++curs_iter; + } + + mCursorMap.clear(); + } + + void SDLCursorManager::setEnabled(bool enabled) + { + if(mInitialized && enabled == mEnabled) + return; + + mInitialized = true; + mEnabled = enabled; + + //turn on hardware cursors + if(enabled) + { + _setGUICursor(mCurrentCursor); + } + //turn off hardware cursors + else + { + if(!mDebug) + SDL_ShowCursor(SDL_FALSE); + } + } + + bool SDLCursorManager::cursorChanged(const std::string &name) + { + mCurrentCursor = name; + + CursorMap::const_iterator curs_iter = mCursorMap.find(name); + + //we have this cursor + if(curs_iter != mCursorMap.end()) + { + _setGUICursor(name); + + return false; + } + else + { + //they should get back to us with more info + return true; + } + } + + void SDLCursorManager::_setGUICursor(const std::string &name) + { + if(mEnabled && (mDebug || mCursorVisible)) + { + SDL_SetCursor(mCursorMap.find(name)->second); + _setCursorVisible(mCursorVisible); + } + } + + void SDLCursorManager::_setCursorVisible(bool visible) + { + if(!mEnabled) + return; + + if(mDebug) + visible = true; + + SDL_ShowCursor(visible ? SDL_TRUE : SDL_FALSE); + } + + void SDLCursorManager::cursorVisibilityChange(bool visible) + { + mCursorVisible = visible; + + _setGUICursor(mCurrentCursor); + _setCursorVisible(visible); + } + + void SDLCursorManager::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); + } + + /// \brief creates an SDL cursor from an Ogre texture + void SDLCursorManager::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) + { + //get the surfaces set up + Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); + buffer.get()->lock(Ogre::HardwarePixelBuffer::HBL_READ_ONLY); + + std::string tempName = "_" + name + "_processing"; + + //we need to copy this to a temporary texture first because the cursors might be in DDS format, + //and Ogre doesn't have an interface to read DDS + Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( + tempName, + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, + size_x, size_y, + 0, + Ogre::PF_FLOAT16_RGBA, + Ogre::TU_STATIC); + + tempTexture->getBuffer()->blit(buffer); + buffer->unlock(); + + // now blit to memory + Ogre::Image destImage; + tempTexture->convertToImage(destImage); + + SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); + + + //copy the Ogre texture to an SDL surface + for(size_t x = 0; x < size_x; ++x) + { + for(size_t y = 0; y < size_y; ++y) + { + Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); + + //set the pixel on the SDL surface to the same value as the Ogre texture's + _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); + } + } + + //set the cursor and store it for later + SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); + mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); + + //clean up + SDL_FreeSurface(surf); + Ogre::TextureManager::getSingleton().remove(tempName); + + _setGUICursor(name); + } + + void SDLCursorManager::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) + { + int bpp = surface->format->BytesPerPixel; + /* Here p is the address to the pixel we want to set */ + Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; + + switch(bpp) { + case 1: + *p = pixel; + break; + + case 2: + *(Uint16 *)p = pixel; + break; + + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { + p[0] = (pixel >> 16) & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = pixel & 0xff; + } else { + p[0] = pixel & 0xff; + p[1] = (pixel >> 8) & 0xff; + p[2] = (pixel >> 16) & 0xff; + } + break; + + case 4: + *(Uint32 *)p = pixel; + break; + } + } +} diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp new file mode 100644 index 0000000000..2de1923775 --- /dev/null +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -0,0 +1,44 @@ +#ifndef _SDL4OGRE_CURSORMANAGER_H +#define _SDL4OGRE_CURSORMANAGER_H + +#include "SDL.h" + +#include "cursormanager.hpp" +#include + +namespace SFO +{ + class SDLCursorManager : + public CursorManager + { + public: + SDLCursorManager(bool debug=false); + virtual ~SDLCursorManager(); + + virtual void setEnabled(bool enabled); + + virtual bool cursorChanged(const std::string &name); + virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + virtual void cursorVisibilityChange(bool visible); + + private: + void _createCursorFromResource(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); + void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); + + void _setGUICursor(const std::string& name); + void _setCursorVisible(bool visible); + + typedef std::map CursorMap; + CursorMap mCursorMap; + + SDL_Cursor* mDebugCursor; + std::string mCurrentCursor; + bool mEnabled; + bool mInitialized; + bool mCursorVisible; + bool mDebug; + + }; +} + +#endif diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index b6761e883e..529740d5ef 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX @@ -28,8 +27,8 @@ namespace SFO mMouseY(0), mMouseX(0) { - _start(); _setupOISKeys(); + _start(); } InputWrapper::~InputWrapper() @@ -38,82 +37,60 @@ namespace SFO SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; - CursorMap::const_iterator curs_iter = mCursorMap.begin(); - - while(curs_iter != mCursorMap.end()) - { - SDL_FreeCursor(curs_iter->second); - ++curs_iter; - } - - mCursorMap.clear(); - SDL_StopTextInput(); SDL_Quit(); } bool InputWrapper::_start() { - Uint32 flags = SDL_INIT_VIDEO; - if(SDL_WasInit(flags) == 0) - { - //get the HWND from ogre's renderwindow - size_t windowHnd; - mWindow->getCustomAttribute("WINDOW", &windowHnd); + //get the HWND from ogre's renderwindow + size_t windowHnd; + mWindow->getCustomAttribute("WINDOW", &windowHnd); - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(SDL_INIT_VIDEO) != 0) - return false; + //wrap our own event handler around ogre's + mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); - //wrap our own event handler around ogre's - mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + if(mSDLWindow == NULL) + return false; - if(mSDLWindow == NULL) - return false; + //without this SDL will take ownership of the window and iconify it when + //we alt-tab away. + SDL_SetWindowFullscreen(mSDLWindow, 0); - //without this SDL will take ownership of the window and iconify it when - //we alt-tab away. - SDL_SetWindowFullscreen(mSDLWindow, 0); - - //translate our keypresses into text - SDL_StartTextInput(); + //translate our keypresses into text + SDL_StartTextInput(); #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX - //linux-specific event-handling fixups - //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 - SDL_SysWMinfo wm_info; - SDL_VERSION(&wm_info.version); + //linux-specific event-handling fixups + //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 + SDL_SysWMinfo wm_info; + SDL_VERSION(&wm_info.version); - if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) - { - Display* display = wm_info.info.x11.display; - Window w = wm_info.info.x11.window; + if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) + { + Display* display = wm_info.info.x11.display; + Window w = wm_info.info.x11.window; - // Set the input hints so we get keyboard input - XWMHints *wmhints = XAllocWMHints(); - if (wmhints) { - wmhints->input = True; - wmhints->flags = InputHint; - XSetWMHints(display, w, wmhints); - XFree(wmhints); - } - - //make sure to subscribe to XLib's events - XSelectInput(display, w, - (FocusChangeMask | EnterWindowMask | LeaveWindowMask | - ExposureMask | ButtonPressMask | ButtonReleaseMask | - PointerMotionMask | KeyPressMask | KeyReleaseMask | - PropertyChangeMask | StructureNotifyMask | - KeymapStateMask)); - - XFlush(display); + // Set the input hints so we get keyboard input + XWMHints *wmhints = XAllocWMHints(); + if (wmhints) { + wmhints->input = True; + wmhints->flags = InputHint; + XSetWMHints(display, w, wmhints); + XFree(wmhints); } -#endif - SDL_ShowCursor(SDL_FALSE); - } + //make sure to subscribe to XLib's events + XSelectInput(display, w, + (FocusChangeMask | EnterWindowMask | LeaveWindowMask | + ExposureMask | ButtonPressMask | ButtonReleaseMask | + PointerMotionMask | KeyPressMask | KeyReleaseMask | + PropertyChangeMask | StructureNotifyMask | + KeymapStateMask)); + + XFlush(display); + } +#endif return true; } @@ -209,10 +186,11 @@ namespace SFO //eep, wrap the pointer manually if the input driver doesn't support //relative positioning natively - if(SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == -1) + SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); + + if(relative) { - if(relative) - mWrapPointer = true; + mWrapPointer = true; } //now remove all mouse events using the old setting from the queue @@ -222,118 +200,6 @@ namespace SFO SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); } - bool InputWrapper::cursorChanged(const std::string &name) - { - CursorMap::const_iterator curs_iter = mCursorMap.find(name); - - //we have this cursor - if(curs_iter != mCursorMap.end()) - { - SDL_SetCursor(curs_iter->second); - return false; - } - else - { - //they should get back to use with more info - return true; - } - } - - void InputWrapper::cursorVisible(bool visible) - { - SDL_ShowCursor(visible ? SDL_TRUE : SDL_FALSE); - } - - void InputWrapper::receiveCursorInfo(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - _createCursorFromResource(name, tex, size_x, size_y, hotspot_x, hotspot_y); - } - - /// \brief creates an SDL cursor from an Ogre texture - void InputWrapper::_createCursorFromResource(const std::string& name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) - { - //get the surfaces set up - Ogre::HardwarePixelBufferSharedPtr buffer = tex.get()->getBuffer(); - buffer.get()->lock(Ogre::HardwarePixelBuffer::HBL_READ_ONLY); - - std::string tempName = "_" + name + "_processing"; - - //we need to copy this to a temporary texture first because the cursors might be in DDS format, - //and Ogre doesn't have an interface to read DDS - Ogre::TexturePtr tempTexture = Ogre::TextureManager::getSingleton().createManual( - tempName, - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - Ogre::TEX_TYPE_2D, - size_x, size_y, - 0, - Ogre::PF_FLOAT16_RGBA, - Ogre::TU_STATIC); - - tempTexture->getBuffer()->blit(buffer); - buffer->unlock(); - - // now blit to memory - Ogre::Image destImage; - tempTexture->convertToImage(destImage); - - SDL_Surface* surf = SDL_CreateRGBSurface(0,size_x,size_y,32,0xFF000000,0x00FF0000,0x0000FF00,0x000000FF); - - - //copy the Ogre texture to an SDL surface - for(size_t x = 0; x < size_x; ++x) - { - for(size_t y = 0; y < size_y; ++y) - { - Ogre::ColourValue clr = destImage.getColourAt(x, y, 0); - - //set the pixel on the SDL surface to the same value as the Ogre texture's - _putPixel(surf, x, y, SDL_MapRGBA(surf->format, clr.r*255, clr.g*255, clr.b*255, clr.a*255)); - } - } - - //set the cursor and store it for later - SDL_Cursor* curs = SDL_CreateColorCursor(surf, hotspot_x, hotspot_y); - SDL_SetCursor(curs); - mCursorMap.insert(CursorMap::value_type(std::string(name), curs)); - - //clean up - SDL_FreeSurface(surf); - Ogre::TextureManager::getSingleton().remove(tempName); - } - - void InputWrapper::_putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel) - { - int bpp = surface->format->BytesPerPixel; - /* Here p is the address to the pixel we want to set */ - Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp; - - switch(bpp) { - case 1: - *p = pixel; - break; - - case 2: - *(Uint16 *)p = pixel; - break; - - case 3: - if(SDL_BYTEORDER == SDL_BIG_ENDIAN) { - p[0] = (pixel >> 16) & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = pixel & 0xff; - } else { - p[0] = pixel & 0xff; - p[1] = (pixel >> 8) & 0xff; - p[2] = (pixel >> 16) & 0xff; - } - break; - - case 4: - *(Uint32 *)p = pixel; - break; - } - } - /// \brief Internal method for ignoring relative motions as a side effect /// of warpMouse() bool InputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index d37a43e339..5233fee8b6 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -1,7 +1,8 @@ -#ifndef _MWINPUT_SDLINPUTWRAPPER_H -#define _MWINPUT_SDLINPUTWRAPPER_H +#ifndef _SDL4OGRE_SDLINPUTWRAPPER_H +#define _SDL4OGRE_SDLINPUTWRAPPER_H #include "SDL2/SDL_events.h" + #include #include @@ -9,36 +10,14 @@ #include "events.h" -namespace Ogre -{ - class Texture; -} namespace SFO { - - - class CursorChangeClient - { - public: - /// \brief Tell the client that the cursor has changed, giving the - /// name of the cursor we changed to ("arrow", "ibeam", etc) - /// \return Whether the client is interested in more information about the cursor - virtual bool cursorChanged(const std::string &name) = 0; - - /// \brief Follow up a cursorChanged() call with enough info to create an SDL cursor. - virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y) = 0; - - /// \brief Tell the client when the cursor visibility changed - virtual void cursorVisible(bool visible) = 0; - }; - - class InputWrapper : - public CursorChangeClient + class InputWrapper { public: InputWrapper(Ogre::RenderWindow* window); - virtual ~InputWrapper(); + ~InputWrapper(); void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } @@ -51,10 +30,6 @@ namespace SFO bool getMouseRelative() { return mMouseRelative; } void setGrabPointer(bool grab); - virtual bool cursorChanged(const std::string &name); - virtual void receiveCursorInfo(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - virtual void cursorVisible(bool visible); - OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code); void warpMouse(int x, int y); @@ -66,9 +41,6 @@ namespace SFO void _wrapMousePointer(const SDL_MouseMotionEvent &evt); MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); - void _createCursorFromResource(const std::string &name, Ogre::TexturePtr tex, Uint8 size_x, Uint8 size_y, Uint8 hotspot_x, Uint8 hotspot_y); - void _putPixel(SDL_Surface *surface, int x, int y, Uint32 pixel); - void _handleKeyPress(SDL_KeyboardEvent& evt); Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); @@ -80,9 +52,6 @@ namespace SFO typedef boost::unordered_map KeyMap; KeyMap mKeyMap; - typedef std::map CursorMap; - CursorMap mCursorMap; - Uint16 mWarpX; Uint16 mWarpY; bool mWarpCompensate; From eb08f407d3510ba0e6ccd67feb9f6a4ee5914ab7 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 15:38:22 -0400 Subject: [PATCH 0019/1537] Oops, remove resource leak in the input wrapper. --- extern/sdl4ogre/sdlinputwrapper.cpp | 33 +++++++++++------------------ extern/sdl4ogre/sdlinputwrapper.hpp | 1 - 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 529740d5ef..0a0e321bb2 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -28,21 +28,7 @@ namespace SFO mMouseX(0) { _setupOISKeys(); - _start(); - } - InputWrapper::~InputWrapper() - { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; - - SDL_StopTextInput(); - SDL_Quit(); - } - - bool InputWrapper::_start() - { //get the HWND from ogre's renderwindow size_t windowHnd; mWindow->getCustomAttribute("WINDOW", &windowHnd); @@ -50,12 +36,11 @@ namespace SFO //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); - if(mSDLWindow == NULL) - return false; + assert(mSDLWindow != NULL); //without this SDL will take ownership of the window and iconify it when //we alt-tab away. - SDL_SetWindowFullscreen(mSDLWindow, 0); + //SDL_SetWindowFullscreen(mSDLWindow, 0); //translate our keypresses into text SDL_StartTextInput(); @@ -91,14 +76,20 @@ namespace SFO XFlush(display); } #endif - return true; + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + + SDL_StopTextInput(); + SDL_Quit(); } void InputWrapper::capture() { - if(!_start()) - throw std::runtime_error(SDL_GetError()); - SDL_Event evt; while(SDL_PollEvent(&evt)) { diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 5233fee8b6..d3c172b493 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -35,7 +35,6 @@ namespace SFO void warpMouse(int x, int y); private: - bool _start(); bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); void _wrapMousePointer(const SDL_MouseMotionEvent &evt); From b6ec64485c21689375ee7823dc05794bb594c47c Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 17:52:26 -0400 Subject: [PATCH 0020/1537] fix includes for Windows --- apps/openmw/engine.cpp | 4 +++- apps/openmw/mwgui/windowmanagerimp.cpp | 4 ++-- cmake/FindSDL2.cmake | 1 + extern/oics/ICSPrerequisites.h | 10 +++++----- extern/sdl4ogre/OISCompat.h | 4 ++-- extern/sdl4ogre/cursormanager.hpp | 2 +- extern/sdl4ogre/events.h | 2 +- extern/sdl4ogre/sdlcursormanager.hpp | 2 +- extern/sdl4ogre/sdlinputwrapper.cpp | 2 +- extern/sdl4ogre/sdlinputwrapper.hpp | 4 ++-- 10 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 51dbabba51..042d10a937 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,4 +1,7 @@ #include "engine.hpp" + +#include + #include "components/esm/loadcell.hpp" #include @@ -36,7 +39,6 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" -#include "SDL2/SDL.h" void OMW::Engine::executeLocalScripts() diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 20301b1b22..e096ee1fb7 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -4,8 +4,8 @@ #include #include "MyGUI_UString.h" -#include "MYGUI/MyGUI_IPointer.h" -#include "MYGUI/MyGUI_ResourceImageSetPointer.h" +#include "MyGUI_IPointer.h" +#include "MyGUI_ResourceImageSetPointer.h" #include "MyGUI_TextureUtility.h" #include diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 614426cccf..707f5bc3dc 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -70,6 +70,7 @@ # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) + FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} diff --git a/extern/oics/ICSPrerequisites.h b/extern/oics/ICSPrerequisites.h index 82c95c86ab..2e107355a4 100644 --- a/extern/oics/ICSPrerequisites.h +++ b/extern/oics/ICSPrerequisites.h @@ -39,11 +39,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tinyxml.h" -#include "SDL2/SDL_input.h" -#include "SDL2/SDL_keyboard.h" -#include "SDL2/SDL_mouse.h" -#include "SDL2/SDL_joystick.h" -#include "SDL2/SDL_events.h" +#include "SDL_input.h" +#include "SDL_keyboard.h" +#include "SDL_mouse.h" +#include "SDL_joystick.h" +#include "SDL_events.h" /// Define the dll export qualifier if compiling for Windows diff --git a/extern/sdl4ogre/OISCompat.h b/extern/sdl4ogre/OISCompat.h index 04ba2c537d..3cffa143db 100644 --- a/extern/sdl4ogre/OISCompat.h +++ b/extern/sdl4ogre/OISCompat.h @@ -1,8 +1,8 @@ #ifndef _OIS_SDL_COMPAT_H #define _OIS_SDL_COMPAT_H -#include -#include +#include +#include namespace OIS { diff --git a/extern/sdl4ogre/cursormanager.hpp b/extern/sdl4ogre/cursormanager.hpp index 938f5f4c28..b98d69ce36 100644 --- a/extern/sdl4ogre/cursormanager.hpp +++ b/extern/sdl4ogre/cursormanager.hpp @@ -1,7 +1,7 @@ #ifndef _SDL4OGRE_CURSOR_MANAGER_H #define _SDL4OGRE_CURSOR_MANAGER_H -#include "SDL2/SDL_types.h" +#include #include namespace Ogre diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 945daf49a8..5a0146635f 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -1,7 +1,7 @@ #ifndef _SFO_EVENTS_H #define _SFO_EVENTS_H -#include +#include //////////// diff --git a/extern/sdl4ogre/sdlcursormanager.hpp b/extern/sdl4ogre/sdlcursormanager.hpp index 2de1923775..ad371f5517 100644 --- a/extern/sdl4ogre/sdlcursormanager.hpp +++ b/extern/sdl4ogre/sdlcursormanager.hpp @@ -1,7 +1,7 @@ #ifndef _SDL4OGRE_CURSORMANAGER_H #define _SDL4OGRE_CURSORMANAGER_H -#include "SDL.h" +#include #include "cursormanager.hpp" #include diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 0a0e321bb2..da65102e7b 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -1,5 +1,5 @@ #include "sdlinputwrapper.hpp" -#include +#include #include #include diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index d3c172b493..9154ff847c 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -1,9 +1,9 @@ #ifndef _SDL4OGRE_SDLINPUTWRAPPER_H #define _SDL4OGRE_SDLINPUTWRAPPER_H -#include "SDL2/SDL_events.h" +#include -#include +#include #include #include "OISCompat.h" From 2639bc43839154810a5cacda6d0085e03f0aa9ae Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sat, 12 Jan 2013 18:53:00 -0400 Subject: [PATCH 0021/1537] Another temp fix for windows --- cmake/FindSDL2.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/FindSDL2.cmake b/cmake/FindSDL2.cmake index 707f5bc3dc..e0c7feea35 100644 --- a/cmake/FindSDL2.cmake +++ b/cmake/FindSDL2.cmake @@ -166,6 +166,10 @@ IF(SDL2_LIBRARY_TEMP) IF(MINGW) SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP}) ENDIF(MINGW) + + IF(WIN32) + SET(SDL2_LIBRARY_TEMP winmm imm32 version msimg32 ${SDL2_LIBRARY_TEMP}) + ENDIF(WIN32) # Set the final string here so the GUI reflects the final state. SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found") From 043e29c62089159061d74213e055f2c521d68272 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 21:32:45 -0400 Subject: [PATCH 0022/1537] Have SDL manage the window instead of OGRE to work around SDL Windows bugs (grumble) --- apps/openmw/engine.cpp | 90 ++++++++++++++++++++++++----- apps/openmw/engine.hpp | 2 + extern/sdl4ogre/sdlinputwrapper.cpp | 23 +------- libs/openengine/ogre/renderer.cpp | 64 +++++++++++++++++++- libs/openengine/ogre/renderer.hpp | 7 +++ 5 files changed, 150 insertions(+), 36 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 12a5d4be75..0619281d0e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,7 +1,5 @@ #include "engine.hpp" -#include - #include "components/esm/loadcell.hpp" #include @@ -40,6 +38,7 @@ #include "mwmechanics/mechanicsmanagerimp.hpp" +#include void OMW::Engine::executeLocalScripts() { @@ -70,6 +69,8 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) { try { + handleSDLMessages(); + mEnvironment.setFrameDuration (evt.timeSinceLastFrame); // update input @@ -116,6 +117,9 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch); MWBase::Environment::get().getWindowManager()->onFrame(evt.timeSinceLastFrame); + + //Flush any events that weren't handled this frame + SDL_FlushEvents(0x0, 0xFFFFFFFF); } catch (const std::exception& e) { @@ -125,6 +129,65 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) return true; } +void OMW::Engine::handleSDLMessages() +{ + //Pump messages since the last frame + const int max_events = 20; + SDL_Event events[max_events]; + + SDL_PumpEvents(); + int num_events = SDL_PeepEvents(events, max_events, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT); + + bool move_or_resize = false; + + unsigned int size_x = 0; + unsigned int size_y = 0; + + if(num_events != 0) + { + for(int i=0; i < num_events; ++i) + { + switch(events[i].window.event) + { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_MOVED: + printf("Resizing window!\n"); + move_or_resize = true; + size_x = events[i].window.data1; + size_y = events[i].window.data2; + break; + } + } + } + + //handle window movements + if(move_or_resize) + { + mOgre->adjustViewport(); + if(!mOgre->getWindow()->isFullScreen()) + { + SDL_DisplayMode dispMode; + SDL_Window* sdlWindow = mOgre->getSDLWindow(); + + SDL_GetWindowDisplayMode(sdlWindow, &dispMode); + + dispMode.w = size_x; + dispMode.h = size_y; + + SDL_SetWindowDisplayMode(sdlWindow, &dispMode); + + mOgre->getWindow()->windowMovedOrResized(); + mOgre->getWindow()->resize(size_x, size_y); + } + } + + if(SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_QUIT, SDL_QUIT) != 0) + { + //user requested a quit, break out. + mOgre->getRoot()->queueEndRendering(); + } +} + OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mOgre (0) , mFpsLevel(0) @@ -140,6 +203,16 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) { std::srand ( std::time(NULL) ); MWClass::registerClasses(); + + Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; + if(SDL_WasInit(flags) == 0) + { + //kindly ask SDL not to trash our OGL context + //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? + SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); + if(SDL_Init(flags) != 0) + throw std::runtime_error("Couldn't initialize SDL!"); + } } OMW::Engine::~Engine() @@ -147,6 +220,7 @@ OMW::Engine::~Engine() mEnvironment.cleanup(); delete mScriptContext; delete mOgre; + SDL_Quit(); } // Load all BSA files in data directory. @@ -317,7 +391,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "shadows"); addZipResource(mResDir / "mygui" / "Obliviontt.zip"); - // Create the window OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); windowSettings.window_x = settings.getInt("resolution x", "Video"); @@ -325,20 +398,11 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) 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(); - Uint32 flags = SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE; - if(SDL_WasInit(flags) == 0) - { - //kindly ask SDL not to trash our OGL context - //might this be related to http://bugzilla.libsdl.org/show_bug.cgi?id=748 ? - SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - if(SDL_Init(flags) != 0) - throw std::runtime_error("Couldn't initialize SDL!"); - } - // cursor replacer (converts the cursor from the bsa so they can be used by mygui) MWGui::CursorReplace replacer; diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e320c6991b..9714451479 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -103,6 +103,8 @@ namespace OMW void executeLocalScripts(); + void handleSDLMessages(); + virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt); /// Load settings from various files, returns the path to the user settings file diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index da65102e7b..cf864b20fc 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -85,7 +85,6 @@ namespace SFO mSDLWindow = NULL; SDL_StopTextInput(); - SDL_Quit(); } void InputWrapper::capture() @@ -121,24 +120,6 @@ namespace SFO case SDL_KEYUP: mKeyboardListener->keyReleased(evt.key); break; - - case SDL_WINDOWEVENT_FOCUS_GAINED: - mWindowListener->windowFocusChange(true); - break; - case SDL_WINDOWEVENT_FOCUS_LOST: - mWindowListener->windowFocusChange(false); - break; - case SDL_WINDOWEVENT_EXPOSED: - mWindowListener->windowVisibilityChange(true); - break; - case SDL_WINDOWEVENT_HIDDEN: - mWindowListener->windowVisibilityChange(false); - break; - - //SDL traps ^C signals, pass it to OGRE. - case SDL_QUIT: - Ogre::Root::getSingleton().queueEndRendering(); - break; } } } @@ -186,9 +167,7 @@ namespace SFO //now remove all mouse events using the old setting from the queue SDL_PumpEvents(); - - SDL_Event dummy[20]; - SDL_PeepEvents(dummy, 20, SDL_GETEVENT, SDL_MOUSEMOTION, SDL_MOUSEMOTION); + SDL_FlushEvent(SDL_MOUSEMOTION); } /// \brief Internal method for ignoring relative motions as a side effect diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 3cdb005186..7696095ebc 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,6 +1,9 @@ #include "renderer.hpp" #include "fader.hpp" +#include +#include + #include "OgreRoot.h" #include "OgreRenderWindow.h" #include "OgreLogManager.h" @@ -47,11 +50,16 @@ void OgreRenderer::cleanup() delete mRoot; mRoot = NULL; + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + unloadPlugins(); } void OgreRenderer::start() { + //TODO: Check if we still need to do this if we're using SDL's + //message pump #if defined(__APPLE__) && !defined(__LP64__) // OSX Carbon Message Pump do { @@ -214,6 +222,56 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params.insert(std::make_pair("FSAA", settings.fsaa)); params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); + // Create an application window with the following settings: + SDL_Window *window = SDL_CreateWindow( + "OpenMW", // window title + SDL_WINDOWPOS_UNDEFINED, // initial x position + SDL_WINDOWPOS_UNDEFINED, // initial y position + settings.window_x, // width, in pixels + settings.window_y, // height, in pixels + SDL_WINDOW_SHOWN|SDL_WINDOW_RESIZABLE + | (settings.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0) + ); + + + //get the native whnd + struct SDL_SysWMinfo wmInfo; + SDL_VERSION(&wmInfo.version); + + if(-1 == SDL_GetWindowWMInfo(window, &wmInfo)) + throw std::runtime_error("Couldn't get WM Info!"); + + Ogre::String winHandle; + + switch(wmInfo.subsystem) + { +#ifdef WIN32 + case SDL_SYSWM_WINDOWS: + // Windows code + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.win.window); + break; +#elif MACOS + case SDL_SYSWM_COCOA: + //required to make OGRE play nice with our window + params.insert(std::make_pair("macAPI", "cocoa")); + params.insert(std::make_pair("macAPICocoaUseNSView", "true")); + + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.cocoa.window); + break; +#else + case SDL_SYSWM_X11: + winHandle = Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.display); + winHandle += ":0:"; + winHandle += Ogre::StringConverter::toString((unsigned long)wmInfo.info.x11.window); + break; +#endif + default: + throw std::runtime_error("Unexpected WM!"); + break; + } + + params.insert(std::make_pair("externalWindowHandle", winHandle)); + mWindow = mRoot->createRenderWindow(title, settings.window_x, settings.window_y, settings.fullscreen, ¶ms); // create the semi-transparent black background texture used by the GUI. @@ -253,7 +311,11 @@ void OgreRenderer::createScene(const std::string& camName, float fov, float near void OgreRenderer::adjustViewport() { // Alter the camera aspect ratio to match the viewport - mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + if(mCamera != NULL) + { + mView->setDimensions(0, 0, 1, 1); + mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); + } } void OgreRenderer::setWindowEventListener(Ogre::WindowEventListener* listener) diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index a8788dfcaf..7e57af9270 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -31,6 +31,8 @@ #include #endif +struct SDL_Window; + namespace Ogre { #if !defined(__APPLE__) || defined(__LP64__) @@ -74,6 +76,7 @@ namespace OEngine Ogre::Root *mRoot; #endif Ogre::RenderWindow *mWindow; + SDL_Window *mSDLWindow; Ogre::SceneManager *mScene; Ogre::Camera *mCamera; Ogre::Viewport *mView; @@ -99,6 +102,7 @@ namespace OEngine OgreRenderer() : mRoot(NULL) , mWindow(NULL) + , mSDLWindow(NULL) , mScene(NULL) , mCamera(NULL) , mView(NULL) @@ -169,6 +173,9 @@ namespace OEngine /// Get the rendering window Ogre::RenderWindow *getWindow() { return mWindow; } + /// Get the SDL Window + SDL_Window *getSDLWindow() { return mSDLWindow; } + /// Get the scene manager Ogre::SceneManager *getScene() { return mScene; } From 9b485a86ef8e7f5b96f89b78e5fe6a8f18629cbf Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 22:38:22 -0400 Subject: [PATCH 0023/1537] resize the window in a slightly less bad way, fix my check in setUseHardwareCursors to be the right way round --- apps/openmw/engine.cpp | 19 ++++--------------- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0619281d0e..7d08eda032 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -138,7 +138,7 @@ void OMW::Engine::handleSDLMessages() SDL_PumpEvents(); int num_events = SDL_PeepEvents(events, max_events, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT); - bool move_or_resize = false; + bool resize = false; unsigned int size_x = 0; unsigned int size_y = 0; @@ -150,9 +150,8 @@ void OMW::Engine::handleSDLMessages() switch(events[i].window.event) { case SDL_WINDOWEVENT_RESIZED: - case SDL_WINDOWEVENT_MOVED: printf("Resizing window!\n"); - move_or_resize = true; + resize = true; size_x = events[i].window.data1; size_y = events[i].window.data2; break; @@ -161,23 +160,13 @@ void OMW::Engine::handleSDLMessages() } //handle window movements - if(move_or_resize) + if(resize) { - mOgre->adjustViewport(); if(!mOgre->getWindow()->isFullScreen()) { - SDL_DisplayMode dispMode; - SDL_Window* sdlWindow = mOgre->getSDLWindow(); - - SDL_GetWindowDisplayMode(sdlWindow, &dispMode); - - dispMode.w = size_x; - dispMode.h = size_y; - - SDL_SetWindowDisplayMode(sdlWindow, &dispMode); - mOgre->getWindow()->windowMovedOrResized(); mOgre->getWindow()->resize(size_x, size_y); + mOgre->adjustViewport(); } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e096ee1fb7..dbd8e01a2f 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -750,7 +750,7 @@ void WindowManager::setUseHardwareCursors(bool use) { mCursorManager->setEnabled(use); - if(!use) + if(use) { MyGUI::PointerManager::getInstance().setVisible(false); } From 10a3caa50494b0abe3776496fb72dcd5ef73d4f0 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Sun, 13 Jan 2013 23:38:46 -0400 Subject: [PATCH 0024/1537] more resizing fixes from scrawl, share an SDLWindow between the input wrapper and the engine --- apps/openmw/engine.cpp | 10 +---- apps/openmw/mwinput/inputmanagerimp.cpp | 5 +-- apps/openmw/mwinput/inputmanagerimp.hpp | 1 - apps/openmw/mwrender/renderingmanager.cpp | 1 - extern/sdl4ogre/sdlinputwrapper.cpp | 49 ++++++++++++++--------- extern/sdl4ogre/sdlinputwrapper.hpp | 6 ++- libs/openengine/ogre/renderer.cpp | 4 +- 7 files changed, 39 insertions(+), 37 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7d08eda032..3374ba3047 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -150,7 +150,6 @@ void OMW::Engine::handleSDLMessages() switch(events[i].window.event) { case SDL_WINDOWEVENT_RESIZED: - printf("Resizing window!\n"); resize = true; size_x = events[i].window.data1; size_y = events[i].window.data2; @@ -162,12 +161,7 @@ void OMW::Engine::handleSDLMessages() //handle window movements if(resize) { - if(!mOgre->getWindow()->isFullScreen()) - { - mOgre->getWindow()->windowMovedOrResized(); - mOgre->getWindow()->resize(size_x, size_y); - mOgre->adjustViewport(); - } + mOgre->getWindow()->resize(size_x, size_y); } if(SDL_PeepEvents(NULL, 1, SDL_PEEKEVENT, SDL_QUIT, SDL_QUIT) != 0) @@ -436,7 +430,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setInputManager (new MWInput::InputManager (*mOgre, MWBase::Environment::get().getWorld()->getPlayer(), - *MWBase::Environment::get().getWindowManager(), mDebug, *this, keybinderUser, keybinderUserExists)); + *MWBase::Environment::get().getWindowManager(), *this, keybinderUser, keybinderUserExists)); // load cell ESM::Position pos; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9d80de91e4..ab873c6861 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -31,7 +31,6 @@ namespace MWInput InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, MWWorld::Player &player, MWBase::WindowManager &windows, - bool debug, OMW::Engine& engine, const std::string& userFile, bool userFileExists) : mOgre(ogre) @@ -45,7 +44,7 @@ namespace MWInput , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) - , mDebug(debug) + , mDebug(Settings::Manager::getBool("debug", "Engine")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -63,7 +62,7 @@ namespace MWInput Ogre::RenderWindow* window = ogre.getWindow (); - mInputManager = new SFO::InputWrapper(window); + mInputManager = new SFO::InputWrapper(mOgre.getSDLWindow()); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 34ea92a374..9832be9a68 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -62,7 +62,6 @@ namespace MWInput InputManager(OEngine::Render::OgreRenderer &_ogre, MWWorld::Player&_player, MWBase::WindowManager &_windows, - bool debug, OMW::Engine& engine, const std::string& userFile, bool userFileExists); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index ae7d6612bd..5d2a5c9514 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -839,7 +839,6 @@ void RenderingManager::windowResized(Ogre::RenderWindow* rw) Settings::Manager::setInt("resolution x", "Video", rw->getWidth()); Settings::Manager::setInt("resolution y", "Video", rw->getHeight()); - mRendering.adjustViewport(); mCompositors->recreate(); mWater->assignTextures(); diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index cf864b20fc..464d8cb6a6 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -16,9 +16,9 @@ namespace SFO { /// \brief General purpose wrapper for OGRE applications around SDL's event /// queue, mostly used for handling input-related events. - InputWrapper::InputWrapper(Ogre::RenderWindow *window) : - mWindow(window), - mSDLWindow(NULL), + InputWrapper::InputWrapper(SDL_Window* window) : + mSDLWindow(window), + mOwnWindow(false), mWarpCompensate(false), mMouseRelative(false), mGrabPointer(false), @@ -29,9 +29,27 @@ namespace SFO { _setupOISKeys(); + SDL_StartTextInput(); + } + + InputWrapper::~InputWrapper() + { + if(mSDLWindow != NULL && mOwnWindow) + SDL_DestroyWindow(mSDLWindow); + mSDLWindow = NULL; + + SDL_StopTextInput(); + } + + void InputWrapper::initFromRenderWindow(Ogre::RenderWindow *win) + { + assert(mSDLWindow == NULL); + + mOwnWindow = true; + //get the HWND from ogre's renderwindow size_t windowHnd; - mWindow->getCustomAttribute("WINDOW", &windowHnd); + win->getCustomAttribute("WINDOW", &windowHnd); //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); @@ -42,9 +60,6 @@ namespace SFO //we alt-tab away. //SDL_SetWindowFullscreen(mSDLWindow, 0); - //translate our keypresses into text - SDL_StartTextInput(); - #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups //see http://bugzilla.libsdl.org/show_bug.cgi?id=730 @@ -78,15 +93,6 @@ namespace SFO #endif } - InputWrapper::~InputWrapper() - { - if(mSDLWindow != NULL) - SDL_DestroyWindow(mSDLWindow); - mSDLWindow = NULL; - - SDL_StopTextInput(); - } - void InputWrapper::capture() { SDL_Event evt; @@ -158,11 +164,14 @@ namespace SFO //eep, wrap the pointer manually if the input driver doesn't support //relative positioning natively - SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); + int success = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE); if(relative) { - mWrapPointer = true; + if(success != 0) + { + mWrapPointer = true; + } } //now remove all mouse events using the old setting from the queue @@ -200,8 +209,8 @@ namespace SFO SDL_GetWindowSize(mSDLWindow, &width, &height); - const int FUDGE_FACTOR_X = width / 4; - const int FUDGE_FACTOR_Y = height / 4; + const int FUDGE_FACTOR_X = width / 8; + const int FUDGE_FACTOR_Y = height / 8; //warp the mouse if it's about to go outside the window if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index 9154ff847c..db4e6f9b00 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -16,9 +16,11 @@ namespace SFO class InputWrapper { public: - InputWrapper(Ogre::RenderWindow* window); + InputWrapper(SDL_Window *window=NULL); ~InputWrapper(); + void initFromRenderWindow(Ogre::RenderWindow* win); + void setMouseEventCallback(MouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(KeyListener* listen) { mKeyboardListener = listen; } void setWindowEventCallback(WindowListener* listen) { mWindowListener = listen; } @@ -62,8 +64,8 @@ namespace SFO Sint32 mMouseX; Sint32 mMouseY; - Ogre::RenderWindow* mWindow; SDL_Window* mSDLWindow; + bool mOwnWindow; }; } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 7696095ebc..0f29b15a09 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -223,7 +223,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& params.insert(std::make_pair("vsync", settings.vsync ? "true" : "false")); // Create an application window with the following settings: - SDL_Window *window = SDL_CreateWindow( + mSDLWindow = SDL_CreateWindow( "OpenMW", // window title SDL_WINDOWPOS_UNDEFINED, // initial x position SDL_WINDOWPOS_UNDEFINED, // initial y position @@ -238,7 +238,7 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& struct SDL_SysWMinfo wmInfo; SDL_VERSION(&wmInfo.version); - if(-1 == SDL_GetWindowWMInfo(window, &wmInfo)) + if(-1 == SDL_GetWindowWMInfo(mSDLWindow, &wmInfo)) throw std::runtime_error("Couldn't get WM Info!"); Ogre::String winHandle; From f85be6a7441d9dfb8b49d40b52a012088c636600 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 07:57:41 -0600 Subject: [PATCH 0025/1537] 80% complete save-on-close feature --- apps/opencs/view/doc/operations.cpp | 2 +- apps/opencs/view/doc/view.cpp | 10 ++- apps/opencs/view/doc/view.hpp | 5 +- apps/opencs/view/doc/viewmanager.cpp | 121 ++++++++++++++++++++++++--- apps/opencs/view/doc/viewmanager.hpp | 7 +- 5 files changed, 129 insertions(+), 16 deletions(-) diff --git a/apps/opencs/view/doc/operations.cpp b/apps/opencs/view/doc/operations.cpp index 71cacbe17e..58cef13430 100644 --- a/apps/opencs/view/doc/operations.cpp +++ b/apps/opencs/view/doc/operations.cpp @@ -54,7 +54,7 @@ void CSVDoc::Operations::quitOperation (int type) mLayout->removeItem ((*iter)->getLayout()); - delete *iter; + (*iter)->deleteLater(); mOperations.erase (iter); if (oldCount > 1) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 6aafef4ed0..49dd2fc8a9 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -18,10 +18,14 @@ #include "operations.hpp" #include "subview.hpp" +#include void CSVDoc::View::closeEvent (QCloseEvent *event) { if (!mViewManager.closeRequest (this)) + { + qDebug() << "ignoring event"; event->ignore(); + } } void CSVDoc::View::setupFileMenu() @@ -117,9 +121,11 @@ void CSVDoc::View::updateActions() mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent) - : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews), QMainWindow (viewParent) +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) //, QMainWindow *viewParent) + : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), + mViewTotal (totalViews) //, QMainWindow (viewParent) { + setAttribute (Qt::WA_DeleteOnClose, true); setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 28ab24b744..f50a0550ee 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -67,7 +67,7 @@ namespace CSVDoc public: - View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews, QMainWindow *viewParent); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); //, QMainWindow *viewParent); ///< The ownership of \a document is not transferred to *this. virtual ~View(); @@ -94,6 +94,8 @@ namespace CSVDoc void addSubView (const CSMWorld::UniversalId& id); + void abortOperation (int type); + private slots: void newView(); @@ -106,7 +108,6 @@ namespace CSVDoc void addGmstsSubView(); - void abortOperation (int type); }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a8faefb970..59e53dfe07 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -12,6 +12,10 @@ #include "view.hpp" +#include +#include + + void CSVDoc::ViewManager::updateIndices() { std::map > documents; @@ -31,7 +35,7 @@ void CSVDoc::ViewManager::updateIndices() } CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) -: mDocumentManager (documentManager) + : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; @@ -59,9 +63,9 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } - QMainWindow *mainWindow = new QMainWindow; + // QMainWindow *mainWindow = new QMainWindow; - View *view = new View (*this, document, countViews (document)+1, mainWindow); + View *view = new View (*this, document, countViews (document)+1); //, mainWindow); mViews.push_back (view); @@ -90,6 +94,8 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { std::vector::iterator iter = std::find (mViews.begin(), mViews.end(), view); + bool continueWithClose = true; + if (iter!=mViews.end()) { bool last = countViews (view->getDocument())<=1; @@ -97,16 +103,98 @@ bool CSVDoc::ViewManager::closeRequest (View *view) /// \todo check if save is in progress -> warn user about possible data loss /// \todo check if document has not been saved -> return false and start close dialogue - mViews.erase (iter); - view->deleteLater(); + CSMDoc::Document *document = view->getDocument(); - if (last) - mDocumentManager.removeDocument (view->getDocument()); - else - updateIndices(); + //notify user of unsaved changes and process response + if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (view); + + //notify user of saving in progress + if ( document->getState() & CSMDoc::State_Saving ) + continueWithClose = showSaveInProgressMessageBox (view); + + qDebug() << "Continue with close? " << continueWithClose; + + if (continueWithClose) + { + mViews.erase (iter); + + if (last) + mDocumentManager.removeDocument (document); + else + updateIndices(); + } } - return true; + return continueWithClose; +} + +bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) +{ + QMessageBox messageBox; + + messageBox.setText ("The document has been modified."); + messageBox.setInformativeText ("Do you want to save your changes?"); + messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + messageBox.setDefaultButton (QMessageBox::Save); + + bool retVal = true; + + switch (messageBox.exec()) + { + case QMessageBox::Save: + view->getDocument()->save(); + mCloseMeOnSaveStateChange = view; + retVal = false; + break; + + case QMessageBox::Discard: + break; + + case QMessageBox::Cancel: + retVal = false; + break; + + default: + break; + + } + + return retVal; +} + +bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) +{ + QMessageBox messageBox; + + messageBox.setText ("The document is currently being saved."); + messageBox.setInformativeText("Do you want to abort the save?"); + messageBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + + bool retVal = false; + + switch (messageBox.exec()) + { + case QMessageBox::Yes: + view->abortOperation(CSMDoc::State_Saving); + // mCloseMeOnSaveStateChange = view; + retVal = false; + break; + + case QMessageBox::No: + //mCloseMeOnSaveStateChange = view; + retVal = false; + break; + + case QMessageBox::Cancel: + retVal = false; + break; + + default: + break; + } + + return retVal; } void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *document) @@ -114,6 +202,19 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); + + if (mPreviousDocumentState & CSMDoc::State_Saving) + qDebug() << "Last state was saving"; + else + qDebug() << "Last state was something else"; +/* + if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) + { + mCloseMeOnSaveStateChange->close(); + mCloseMeOnSaveStateChange = 0; + } +*/ + mPreviousDocumentState = state; } void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document) diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 72e7a3e1a1..2517f8ccbe 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -27,12 +27,17 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; + View *mCloseMeOnSaveStateChange; + int mPreviousDocumentState; // not implemented ViewManager (const ViewManager&); ViewManager& operator= (const ViewManager&); void updateIndices(); + bool showModifiedDocumentMessageBox (View* view); + bool showSaveInProgressMessageBox (View* view); + public: @@ -63,4 +68,4 @@ namespace CSVDoc } -#endif \ No newline at end of file +#endif From a2e36594c97eface26fabeee13c27e1f84ff8351 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 09:22:44 -0600 Subject: [PATCH 0026/1537] Completed "abort save on close" feature --- apps/opencs/view/doc/view.cpp | 4 ++-- apps/opencs/view/doc/view.hpp | 2 +- apps/opencs/view/doc/viewmanager.cpp | 23 ++++++++++++----------- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 49dd2fc8a9..b4d137be2e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -121,9 +121,9 @@ void CSVDoc::View::updateActions() mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); } -CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) //, QMainWindow *viewParent) +CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), - mViewTotal (totalViews) //, QMainWindow (viewParent) + mViewTotal (totalViews) { setAttribute (Qt::WA_DeleteOnClose, true); setDockOptions (QMainWindow::AllowNestedDocks); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index f50a0550ee..d436aebe76 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -67,7 +67,7 @@ namespace CSVDoc public: - View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); //, QMainWindow *viewParent); + View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); ///< The ownership of \a document is not transferred to *this. virtual ~View(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 59e53dfe07..02407dfcde 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -171,22 +171,22 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) messageBox.setInformativeText("Do you want to abort the save?"); messageBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); - bool retVal = false; + bool retVal = true; switch (messageBox.exec()) { - case QMessageBox::Yes: + case QMessageBox::Yes: //immediate shutdown + mCloseMeOnSaveStateChange = 0; view->abortOperation(CSMDoc::State_Saving); - // mCloseMeOnSaveStateChange = view; + break; + + case QMessageBox::No: //shutdown after save completes + mCloseMeOnSaveStateChange = view; retVal = false; break; - case QMessageBox::No: - //mCloseMeOnSaveStateChange = view; - retVal = false; - break; - - case QMessageBox::Cancel: + case QMessageBox::Cancel: //abort shutdown, allow save to complete + mCloseMeOnSaveStateChange = 0; retVal = false; break; @@ -207,13 +207,14 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc qDebug() << "Last state was saving"; else qDebug() << "Last state was something else"; -/* + + //mechanism to shutdown main window after saving operation completes if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) { mCloseMeOnSaveStateChange->close(); mCloseMeOnSaveStateChange = 0; } -*/ + mPreviousDocumentState = state; } From bf6c855e6d829ca2f54abc380f6653cb0a5e3626 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 12:49:26 -0600 Subject: [PATCH 0027/1537] Final changes to implement save-on-close features --- apps/opencs/view/doc/view.cpp | 9 +++--- apps/opencs/view/doc/viewmanager.cpp | 41 +++++++++++++++------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index fea121aa0d..0a8759fa1f 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -18,14 +18,10 @@ #include "operations.hpp" #include "subview.hpp" -#include void CSVDoc::View::closeEvent (QCloseEvent *event) { if (!mViewManager.closeRequest (this)) - { - qDebug() << "ignoring event"; event->ignore(); - } } void CSVDoc::View::setupFileMenu() @@ -43,6 +39,11 @@ void CSVDoc::View::setupFileMenu() mSave = new QAction (tr ("&Save"), this); connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + + QAction *exit = new QAction (tr ("&Exit"), this); + connect (exit, SIGNAL (triggered()), this, SLOT (close())); + file->addAction(exit); + } void CSVDoc::View::setupEditMenu() diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 02407dfcde..a5c7910c0f 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -12,7 +12,6 @@ #include "view.hpp" -#include #include @@ -105,15 +104,13 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - //notify user of unsaved changes and process response - if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (view); - //notify user of saving in progress if ( document->getState() & CSMDoc::State_Saving ) continueWithClose = showSaveInProgressMessageBox (view); - - qDebug() << "Continue with close? " << continueWithClose; + else + //notify user of unsaved changes and process response + if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (view); if (continueWithClose) { @@ -144,8 +141,13 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) { case QMessageBox::Save: view->getDocument()->save(); - mCloseMeOnSaveStateChange = view; - retVal = false; + + retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); + + if (!retVal) + mCloseMeOnSaveStateChange = view; + else + mCloseMeOnSaveStateChange = 0; break; case QMessageBox::Discard: @@ -181,8 +183,16 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) break; case QMessageBox::No: //shutdown after save completes + + //return true (continue with close) if the save operation ended before the + //user clicked "No" + retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); + + if (!retVal) mCloseMeOnSaveStateChange = view; - retVal = false; + else + mCloseMeOnSaveStateChange = 0; + break; case QMessageBox::Cancel: //abort shutdown, allow save to complete @@ -203,17 +213,10 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); - if (mPreviousDocumentState & CSMDoc::State_Saving) - qDebug() << "Last state was saving"; - else - qDebug() << "Last state was something else"; - //mechanism to shutdown main window after saving operation completes if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) - { - mCloseMeOnSaveStateChange->close(); - mCloseMeOnSaveStateChange = 0; - } + if (mCloseMeOnSaveStateChange->close()) + mCloseMeOnSaveStateChange = 0; mPreviousDocumentState = state; } From eb90bd71badf66f7368f2c936c3b844ab7b3076a Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sat, 2 Mar 2013 21:34:55 -0600 Subject: [PATCH 0028/1537] Fixed triggering confirmation messages boxes when more than one view is open. --- apps/opencs/view/doc/viewmanager.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a5c7910c0f..63dd18291c 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -62,9 +62,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) this, SLOT (progress (int, int, int, int, CSMDoc::Document *))); } - // QMainWindow *mainWindow = new QMainWindow; - - View *view = new View (*this, document, countViews (document)+1); //, mainWindow); + View *view = new View (*this, document, countViews (document)+1); mViews.push_back (view); @@ -104,18 +102,21 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - //notify user of saving in progress - if ( document->getState() & CSMDoc::State_Saving ) - continueWithClose = showSaveInProgressMessageBox (view); - else - //notify user of unsaved changes and process response - if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (view); + if (last) + { + //notify user of saving in progress + if ( (document->getState() & CSMDoc::State_Saving) ) + continueWithClose = showSaveInProgressMessageBox (view); + else + //notify user of unsaved changes and process response + if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (view); + } + + mViews.erase (iter); if (continueWithClose) { - mViews.erase (iter); - if (last) mDocumentManager.removeDocument (document); else From 6911868f2af56b48f2884e65092e0bbb52e14f56 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sun, 3 Mar 2013 15:58:26 -0600 Subject: [PATCH 0029/1537] File->close and File->exit menu items added. Exit uses closeAllWindows() to ensure ViewManager::closeRequest is called on the last open window. Exit will close all open windows but the last one in cases of active save operation or modified file. --- apps/opencs/editor.cpp | 4 +++- apps/opencs/view/doc/view.cpp | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index e2df365a29..98b67142a5 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -58,5 +58,7 @@ int CS::Editor::run() { mStartup.show(); + QApplication::setQuitOnLastWindowClosed (true); + return QApplication::exec(); -} \ No newline at end of file +} diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 0a8759fa1f..78eba78801 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../../model/doc/document.hpp" @@ -40,10 +41,15 @@ void CSVDoc::View::setupFileMenu() connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + QAction *close = new QAction (tr ("&Close"), this); + connect (close, SIGNAL (triggered()), this, SLOT (close())); + file->addAction(close); + QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), this, SLOT (close())); + connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); file->addAction(exit); + } void CSVDoc::View::setupEditMenu() From 5fc7103425732403a0b8e6f092430a2996138488 Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 20:31:47 +0000 Subject: [PATCH 0030/1537] First attempt at pathfinding using boost::graph --- apps/openmw/mwmechanics/aitravel.cpp | 193 ++++++++++++++++++++++++++- apps/openmw/mwmechanics/aitravel.hpp | 7 +- 2 files changed, 196 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 897dd17480..b5e67e449b 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -1,8 +1,19 @@ #include "aitravel.hpp" #include +#include "character.hpp" + +#include "../mwworld/class.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "movement.hpp" + +#include +#include +#include "boost/tuple/tuple.hpp" + MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z) +: mX(x),mY(y),mZ(z),isPathConstructed(false) { } @@ -11,10 +22,186 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distance(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); +} + +float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) +{ + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); +} + +int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) +{ + if(!grid) throw std::exception("NULL PathGrid!"); + if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(int i=1; imPoints.size();i++) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + + return i0; +} + +float sgn(float a) +{ + if(a>0) return 1.; + else return -1.; +} + +float getZAngle(float dX,float dY) +{ + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); +} + +struct Edge +{ + float distance; +}; + +typedef boost::adjacency_list,boost::property > PathGridGraph; +typedef boost::property_map::type WeightMap; +typedef PathGridGraph::vertex_descriptor PointID; +typedef PathGridGraph::edge_descriptor PointConnectionID; + +struct found_path {}; + +class goalVisited : public boost::default_astar_visitor +{ +public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } +private: + PointID mGoal; +}; + +class DistanceHeuristic : public boost::astar_heuristic +{ +public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } +private: + const PathGridGraph & mGraph; + PointID mGoal; +}; + +std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; +} + +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +{ + PathGridGraph graph; + + for(int i = 0;imPoints.size();i++) + { + PointID pID = boost::add_vertex(graph); + graph[pID] = pathgrid->mPoints[i]; + } + + for(int i = 0;imEdges.size();i++) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; +} + bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { - std::cout << "AiTravel completed.\n"; - return true; + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + + if(!isPathConstructed) + { + int start = getClosestPoint(pathgrid,pos.pos[0],pos.pos[1],pos.pos[2]); + int end = getClosestPoint(pathgrid,mX,mY,mZ); + + PathGridGraph graph = buildGraph(pathgrid); + + mPath = getPath(start,end,graph); + isPathConstructed = true; + } + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + nextPoint = *mPath.begin(); + } + + float dX = nextPoint.mX - pos.pos[0]; + float dY = nextPoint.mY - pos.pos[1]; + + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; + //return true; } int MWMechanics::AiTravel::getTypeId() const diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 1c6abbf279..a596f4c85d 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,7 +1,9 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H -#include "aipackage.hpp" +#include "aipackage.hpp" +#include "components\esm\loadpgrd.hpp" +#include namespace MWMechanics { @@ -21,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + bool isPathConstructed; + std::list mPath; + }; } From 01908dbcc27f2202e13dce90fe24f77dc268c97c Mon Sep 17 00:00:00 2001 From: gus Date: Wed, 6 Mar 2013 21:17:33 +0000 Subject: [PATCH 0031/1537] little improvement --- apps/openmw/mwmechanics/aitravel.cpp | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b5e67e449b..9d41a080c7 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -22,6 +22,11 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } +float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) +{ + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); +} + float distance(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); @@ -64,11 +69,6 @@ float getZAngle(float dX,float dY) return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); } -struct Edge -{ - float distance; -}; - typedef boost::adjacency_list,boost::property > PathGridGraph; typedef boost::property_map::type WeightMap; @@ -176,6 +176,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid); mPath = getPath(start,end,graph); + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + mPath.push_back(dest); isPathConstructed = true; } if(mPath.empty()) @@ -184,7 +189,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distance(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) + if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) { mPath.pop_front(); if(mPath.empty()) From 03c7f181125e05ebf8a46818f9e616db9a267db7 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Wed, 6 Mar 2013 06:41:33 -0600 Subject: [PATCH 0032/1537] Fixes for save-on-close message boxes --- apps/opencs/CMakeLists.txt | 1 - apps/opencs/model/doc/document.cpp | 7 +- apps/opencs/view/doc/view.cpp | 19 ++-- apps/opencs/view/doc/view.hpp | 10 +- apps/opencs/view/doc/viewmanager.cpp | 156 ++++++++++++++++++--------- apps/opencs/view/doc/viewmanager.hpp | 17 ++- 6 files changed, 141 insertions(+), 69 deletions(-) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index d5d389a141..0446d921ff 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -1,4 +1,3 @@ - set (OPENCS_SRC main.cpp) opencs_units (. editor) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index b361577bec..2cdd1f5383 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -287,11 +287,13 @@ void CSMDoc::Document::abortOperation (int type) } } + void CSMDoc::Document::modificationStateChanged (bool clean) { emit stateChanged (getState(), this); } + void CSMDoc::Document::operationDone (int type) { emit stateChanged (getState(), this); @@ -305,9 +307,12 @@ void CSMDoc::Document::saving() if (mSaveCount>15) { + //clear the stack before resetting the save state + //to avoid emitting incorrect states + mUndoStack.setClean(); + mSaveCount = 0; mSaveTimer.stop(); - mUndoStack.setClean(); emit stateChanged (getState(), this); } } diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 78eba78801..29aa471fdf 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,10 +46,10 @@ void CSVDoc::View::setupFileMenu() file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); + connect (exit, SIGNAL (triggered()), this, SLOT (exitApplication())); + connect (this, SIGNAL (closeAllViews(View *)), &mViewManager, SLOT (closeAllViews(View *))); + file->addAction(exit); - - } void CSVDoc::View::setupEditMenu() @@ -132,13 +132,11 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - setAttribute (Qt::WA_DeleteOnClose, true); setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size - mSubViewWindow = new QMainWindow(); - setCentralWidget (mSubViewWindow); + setCentralWidget (&mSubViewWindow); mOperations = new Operations; addDockWidget (Qt::BottomDockWidgetArea, mOperations); @@ -213,7 +211,7 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id) /// \todo add an user setting to reuse sub views (on a per document basis or on a per top level view basis) SubView *view = mSubViewFactory.makeSubView (id, *mDocument); - mSubViewWindow->addDockWidget (Qt::TopDockWidgetArea, view); + mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&)), this, SLOT (addSubView (const CSMWorld::UniversalId&))); @@ -252,7 +250,12 @@ void CSVDoc::View::abortOperation (int type) updateActions(); } -QDockWidget *CSVDoc::View::getOperations() const +CSVDoc::Operations *CSVDoc::View::getOperations() const { return mOperations; } + +void CSVDoc::View::exitApplication() +{ + emit closeAllViews (this); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index d436aebe76..d6b6ad4601 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -41,7 +41,8 @@ namespace CSVDoc std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; - QMainWindow* mSubViewWindow; + QMainWindow mSubViewWindow; + // not implemented View (const View&); @@ -68,6 +69,7 @@ namespace CSVDoc public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); + ///< The ownership of \a document is not transferred to *this. virtual ~View(); @@ -82,7 +84,7 @@ namespace CSVDoc void updateProgress (int current, int max, int type, int threads); - QDockWidget *getOperations() const; + Operations *getOperations() const; signals: @@ -90,6 +92,8 @@ namespace CSVDoc void loadDocumentRequest(); + void closeAllViews (View *); + public slots: void addSubView (const CSMWorld::UniversalId& id); @@ -108,6 +112,8 @@ namespace CSVDoc void addGmstsSubView(); + void exitApplication(); + }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 63dd18291c..9bb96167d9 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -13,7 +13,7 @@ #include "view.hpp" #include - +#include void CSVDoc::ViewManager::updateIndices() { @@ -34,7 +34,7 @@ void CSVDoc::ViewManager::updateIndices() } CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) - : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0) + : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0), mUserWarned(false) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; @@ -46,6 +46,7 @@ CSVDoc::ViewManager::~ViewManager() { delete mDelegateFactories; + //not needed due to deletion in ViewManager::closeRequest? for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } @@ -64,6 +65,7 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document) View *view = new View (*this, document, countViews (document)+1); + mViews.push_back (view); view->show(); @@ -106,17 +108,18 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { //notify user of saving in progress if ( (document->getState() & CSMDoc::State_Saving) ) - continueWithClose = showSaveInProgressMessageBox (view); - else - //notify user of unsaved changes and process response - if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (view); - } + continueWithClose = showSaveInProgressMessageBox (iter); - mViews.erase (iter); + //notify user of unsaved changes and process response + else if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (iter); + } if (continueWithClose) { + (*iter)->deleteLater(); + mViews.erase (iter); + if (last) mDocumentManager.removeDocument (document); else @@ -127,7 +130,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view) return continueWithClose; } -bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) +bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::iterator viewIter) { QMessageBox messageBox; @@ -138,23 +141,32 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) bool retVal = true; - switch (messageBox.exec()) + connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + mUserWarned = true; + + int response = messageBox.exec(); + + mUserWarned = false; + + switch (response) { case QMessageBox::Save: - view->getDocument()->save(); - retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); - - if (!retVal) - mCloseMeOnSaveStateChange = view; - else - mCloseMeOnSaveStateChange = 0; + (*viewIter)->getDocument()->save(); + mCloseMeOnSaveStateChange = viewIter; + retVal = false; break; case QMessageBox::Discard: + + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); break; case QMessageBox::Cancel: + + //disconnect to prevent unintended view closures + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); retVal = false; break; @@ -166,43 +178,55 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (View* view) return retVal; } -bool CSVDoc::ViewManager::showSaveInProgressMessageBox (View* view) +bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::iterator viewIter) { QMessageBox messageBox; messageBox.setText ("The document is currently being saved."); - messageBox.setInformativeText("Do you want to abort the save?"); - messageBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel); + messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?"); + + QPushButton* waitButton = messageBox.addButton (tr("Wait"), QMessageBox::YesRole); + QPushButton* closeButton = messageBox.addButton (tr("Close Now"), QMessageBox::RejectRole); + QPushButton* cancelButton = messageBox.addButton (tr("Cancel"), QMessageBox::NoRole); + + messageBox.setDefaultButton (waitButton); bool retVal = true; - switch (messageBox.exec()) + //Connections shut down message box if operation ends before user makes a decision. + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); + + //set / clear the user warned flag to indicate whether or not the message box is currently active. + mUserWarned = true; + + messageBox.exec(); + + mUserWarned = false; + + //if closed by the warning handler, defaults to the RejectRole button (closeButton) + if (messageBox.clickedButton() == waitButton) { - case QMessageBox::Yes: //immediate shutdown - mCloseMeOnSaveStateChange = 0; - view->abortOperation(CSMDoc::State_Saving); - break; + //save the View iterator for shutdown after the save operation ends + mCloseMeOnSaveStateChange = viewIter; + retVal = false; + } - case QMessageBox::No: //shutdown after save completes + else if (messageBox.clickedButton() == closeButton) + { + //disconnect to avoid segmentation fault + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + (*viewIter)->abortOperation(CSMDoc::State_Saving); + mCloseMeOnSaveStateChange = mViews.end(); + } - //return true (continue with close) if the save operation ended before the - //user clicked "No" - retVal = !(view->getDocument()->getState() & CSMDoc::State_Saving); - - if (!retVal) - mCloseMeOnSaveStateChange = view; - else - mCloseMeOnSaveStateChange = 0; - - break; - - case QMessageBox::Cancel: //abort shutdown, allow save to complete - mCloseMeOnSaveStateChange = 0; - retVal = false; - break; - - default: - break; + else if (messageBox.clickedButton() == cancelButton) + { + //abort shutdown, allow save to complete + //disconnection to prevent unintended view closures + mCloseMeOnSaveStateChange = mViews.end(); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + retVal = false; } return retVal; @@ -213,13 +237,6 @@ void CSVDoc::ViewManager::documentStateChanged (int state, CSMDoc::Document *doc for (std::vector::const_iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) if ((*iter)->getDocument()==document) (*iter)->updateDocumentState(); - - //mechanism to shutdown main window after saving operation completes - if (mCloseMeOnSaveStateChange && (mPreviousDocumentState & CSMDoc::State_Saving)) - if (mCloseMeOnSaveStateChange->close()) - mCloseMeOnSaveStateChange = 0; - - mPreviousDocumentState = state; } void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, CSMDoc::Document *document) @@ -228,3 +245,38 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, if ((*iter)->getDocument()==document) (*iter)->updateProgress (current, max, type, threads); } + +void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *document) +{ + if ( !(state & CSMDoc::State_Saving) ) + { + //if the user is being warned (message box is active), shut down the message box, + //as there is no save operation currently running + if ( mUserWarned ) + emit closeMessageBox(); + + //otherwise, the user has closed the message box before the save operation ended. + //close the view + else if (mCloseMeOnSaveStateChange!=mViews.end()) + { + (*mCloseMeOnSaveStateChange)->close(); + mCloseMeOnSaveStateChange = mViews.end(); + } + } +} + +void CSVDoc::ViewManager::closeAllViews (View *lastView) +{ + //forces document views to close in an orderly manner + // the last view closed is the view from which the "Exit" action was triggered + while (mViews.size() > 1) + { + std::vector::iterator iter = mViews.begin(); + + if ((*iter) != lastView) + (*iter)->close(); + else (*(++iter))->close(); + } + + lastView->close(); +} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 2517f8ccbe..92df13785f 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -27,17 +27,16 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; - View *mCloseMeOnSaveStateChange; - int mPreviousDocumentState; + std::vector::iterator mCloseMeOnSaveStateChange; + bool mUserWarned; // not implemented ViewManager (const ViewManager&); ViewManager& operator= (const ViewManager&); void updateIndices(); - bool showModifiedDocumentMessageBox (View* view); - bool showSaveInProgressMessageBox (View* view); - + bool showModifiedDocumentMessageBox (std::vector::iterator view); + bool showSaveInProgressMessageBox (std::vector::iterator view); public: @@ -59,11 +58,19 @@ namespace CSVDoc void loadDocumentRequest(); + void closeMessageBox(); + + public slots: + + void closeAllViews (View *lastView); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); void progress (int current, int max, int type, int threads, CSMDoc::Document *document); + + void onCloseWarningHandler(int state, CSMDoc::Document* document); }; } From ce91ef36ead190d6e038f75feee31b2ce1f9db56 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Sun, 10 Mar 2013 07:49:43 -0500 Subject: [PATCH 0033/1537] Fix for warnings on close, leaves all views open until a decision is made --- apps/opencs/view/doc/view.cpp | 8 +------ apps/opencs/view/doc/view.hpp | 2 -- apps/opencs/view/doc/viewmanager.cpp | 31 ++++++---------------------- apps/opencs/view/doc/viewmanager.hpp | 4 ---- 4 files changed, 7 insertions(+), 38 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 29aa471fdf..51d4a5135c 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,8 +46,7 @@ void CSVDoc::View::setupFileMenu() file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), this, SLOT (exitApplication())); - connect (this, SIGNAL (closeAllViews(View *)), &mViewManager, SLOT (closeAllViews(View *))); + connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); file->addAction(exit); } @@ -254,8 +253,3 @@ CSVDoc::Operations *CSVDoc::View::getOperations() const { return mOperations; } - -void CSVDoc::View::exitApplication() -{ - emit closeAllViews (this); -} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index d6b6ad4601..92c57fe9ec 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -112,8 +112,6 @@ namespace CSVDoc void addGmstsSubView(); - void exitApplication(); - }; } diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index eb9744c11c..5614aeda44 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -108,16 +108,13 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - if (last) - { - //notify user of saving in progress - if ( (document->getState() & CSMDoc::State_Saving) ) - continueWithClose = showSaveInProgressMessageBox (iter); + //notify user of saving in progress + if ( (document->getState() & CSMDoc::State_Saving) ) + continueWithClose = showSaveInProgressMessageBox (iter); - //notify user of unsaved changes and process response - else if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (iter); - } + //notify user of unsaved changes and process response + else if ( document->getState() & CSMDoc::State_Modified) + continueWithClose = showModifiedDocumentMessageBox (iter); if (continueWithClose) { @@ -268,19 +265,3 @@ void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *do } } } - -void CSVDoc::ViewManager::closeAllViews (View *lastView) -{ - //forces document views to close in an orderly manner - // the last view closed is the view from which the "Exit" action was triggered - while (mViews.size() > 1) - { - std::vector::iterator iter = mViews.begin(); - - if ((*iter) != lastView) - (*iter)->close(); - else (*(++iter))->close(); - } - - lastView->close(); -} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 92df13785f..82a8b57330 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -60,10 +60,6 @@ namespace CSVDoc void closeMessageBox(); - public slots: - - void closeAllViews (View *lastView); - private slots: void documentStateChanged (int state, CSMDoc::Document *document); From bbc4c23f7e184782eec35bface3e0d10df182dd1 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 10 Mar 2013 15:07:22 +0000 Subject: [PATCH 0034/1537] AITravel now works correctly on exterior cells. As long as NPC don't try to leave cell, it's ok. --- apps/openmw/mwmechanics/aitravel.cpp | 31 ++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 9d41a080c7..09b0efad9c 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -53,7 +53,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - + std::cout << "distance:: " << m << "\n"; return i0; } @@ -135,14 +135,16 @@ std::list getPath(PointID start,PointID end,PathGridGraph return shortest_path; } -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid) +PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; for(int i = 0;imPoints.size();i++) { PointID pID = boost::add_vertex(graph); - graph[pID] = pathgrid->mPoints[i]; + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; } for(int i = 0;imEdges.size();i++) @@ -165,17 +167,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); + ESM::Position pos = actor.getRefData().getPosition(); + //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } - PathGridGraph graph = buildGraph(pathgrid); + int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); + int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); + + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); + if(mPath.empty()) std::cout << "graph doesn't find any way..."; ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -185,6 +196,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { + std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -195,6 +207,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); @@ -205,8 +218,8 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + return false; - //return true; } int MWMechanics::AiTravel::getTypeId() const From 96b62940b399e4f88fb9c415d923a8506e3581af Mon Sep 17 00:00:00 2001 From: graffy76 Date: Mon, 11 Mar 2013 06:38:27 -0500 Subject: [PATCH 0035/1537] Fixes docked subviews becoming tabbed and application closure when closing one of several views. --- apps/opencs/view/doc/view.cpp | 4 +++- apps/opencs/view/doc/viewmanager.cpp | 22 +++++++++++++--------- apps/opencs/view/doc/viewmanager.hpp | 4 +++- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 51d4a5135c..dfbd92a609 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -131,10 +131,12 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - setDockOptions (QMainWindow::AllowNestedDocks); + // setDockOptions (QMainWindow::AllowNestedDocks); resize (300, 300); /// \todo get default size from settings and set reasonable minimal size + mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); + setCentralWidget (&mSubViewWindow); mOperations = new Operations; diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 5614aeda44..83ace49387 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -14,6 +14,8 @@ #include #include +#include +#include void CSVDoc::ViewManager::updateIndices() { @@ -44,6 +46,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + connect (this, SIGNAL (exitApplication()), QApplication::instance(), SLOT (closeAllWindows())); + } CSVDoc::ViewManager::~ViewManager() @@ -143,7 +147,7 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i bool retVal = true; connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); mUserWarned = true; int response = messageBox.exec(); @@ -161,13 +165,13 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i case QMessageBox::Discard: - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); break; case QMessageBox::Cancel: //disconnect to prevent unintended view closures - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; break; @@ -195,7 +199,7 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite bool retVal = true; //Connections shut down message box if operation ends before user makes a decision. - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); //set / clear the user warned flag to indicate whether or not the message box is currently active. @@ -216,7 +220,7 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite else if (messageBox.clickedButton() == closeButton) { //disconnect to avoid segmentation fault - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); (*viewIter)->abortOperation(CSMDoc::State_Saving); mCloseMeOnSaveStateChange = mViews.end(); } @@ -226,7 +230,7 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite //abort shutdown, allow save to complete //disconnection to prevent unintended view closures mCloseMeOnSaveStateChange = mViews.end(); - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onCloseWarningHandler(int, CSMDoc::Document *))); + disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; } @@ -247,7 +251,7 @@ void CSVDoc::ViewManager::progress (int current, int max, int type, int threads, (*iter)->updateProgress (current, max, type, threads); } -void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *document) +void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *document) { if ( !(state & CSMDoc::State_Saving) ) { @@ -257,10 +261,10 @@ void CSVDoc::ViewManager::onCloseWarningHandler (int state, CSMDoc::Document *do emit closeMessageBox(); //otherwise, the user has closed the message box before the save operation ended. - //close the view + //exit the application else if (mCloseMeOnSaveStateChange!=mViews.end()) { - (*mCloseMeOnSaveStateChange)->close(); + emit exitApplication(); mCloseMeOnSaveStateChange = mViews.end(); } } diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index 82a8b57330..b77e5f5758 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -60,13 +60,15 @@ namespace CSVDoc void closeMessageBox(); + void exitApplication(); + private slots: void documentStateChanged (int state, CSMDoc::Document *document); void progress (int current, int max, int type, int threads, CSMDoc::Document *document); - void onCloseWarningHandler(int state, CSMDoc::Document* document); + void onExitWarningHandler(int state, CSMDoc::Document* document); }; } From 64d517dd796a5f07406f909ee25fca81008c920e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Mar 2013 14:42:49 +0100 Subject: [PATCH 0036/1537] removed unused file type information from esm component --- apps/esmtool/esmtool.cpp | 4 ---- components/esm/esmcommon.hpp | 4 ++-- components/esm/esmreader.cpp | 24 ------------------------ components/esm/esmreader.hpp | 3 --- components/esm/esmwriter.cpp | 16 +++------------- components/esm/esmwriter.hpp | 4 +--- 6 files changed, 6 insertions(+), 49 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 3c9476d7a2..b243917be9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -23,7 +23,6 @@ struct ESMData std::string author; std::string description; int version; - int type; ESM::ESMReader::MasterList masters; std::deque mRecords; @@ -284,8 +283,6 @@ int load(Arguments& info) info.data.author = esm.getAuthor(); info.data.description = esm.getDesc(); info.data.masters = esm.getMasters(); - info.data.version = esm.getVer(); - info.data.type = esm.getType(); if (!quiet) { @@ -430,7 +427,6 @@ int clone(Arguments& info) esm.setAuthor(info.data.author); esm.setDescription(info.data.description); esm.setVersion(info.data.version); - esm.setType(info.data.type); for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 335d123378..f5ddf62802 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -41,7 +41,7 @@ union NAME_T { char name[LEN]; int32_t val; - + bool operator==(const char *str) const { for(int i=0; i mBuffer; - SaveData mSaveData; MasterList mMasters; std::vector *mGlobalReaderList; ToUTF8::Utf8Encoder* mEncoder; diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index b9dd5b57b6..faceeeaa6f 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -17,16 +17,6 @@ void ESMWriter::setVersion(int ver) m_header.version = ver; } -int ESMWriter::getType() -{ - return m_header.type; -} - -void ESMWriter::setType(int type) -{ - m_header.type = type; -} - void ESMWriter::setAuthor(const std::string& auth) { strncpy((char*)&m_header.author, auth.c_str(), 32); @@ -86,7 +76,7 @@ void ESMWriter::close() void ESMWriter::startRecord(const std::string& name, uint32_t flags) { m_recordCount++; - + writeName(name); RecordData rec; rec.name = name; @@ -109,7 +99,7 @@ void ESMWriter::startSubRecord(const std::string& name) rec.size = 0; writeT(0); // Size goes here m_records.push_back(rec); - + assert(m_records.back().size == 0); } @@ -118,7 +108,7 @@ void ESMWriter::endRecord(const std::string& name) RecordData rec = m_records.back(); assert(rec.name == name); m_records.pop_back(); - + m_stream->seekp(rec.position); count = false; diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index 94e173b4ce..f488cce3e1 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -22,8 +22,6 @@ class ESMWriter public: int getVersion(); void setVersion(int ver); - int getType(); - void setType(int type); void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); @@ -80,7 +78,7 @@ public: { write((char*)&data, size); } - + void startRecord(const std::string& name, uint32_t flags); void startSubRecord(const std::string& name); void endRecord(const std::string& name); From 2e1a1fd11a4cd0583c2c507eb1aaa203444dbd13 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Mar 2013 16:30:47 +0100 Subject: [PATCH 0037/1537] removing some remains of the removed GMST fixing feature --- apps/esmtool/esmtool.cpp | 3 +-- components/esm/esmcommon.hpp | 11 ----------- components/esm/esmreader.cpp | 12 ------------ components/esm/esmreader.hpp | 2 -- 4 files changed, 1 insertion(+), 27 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index b243917be9..8d060cbd22 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -288,8 +288,7 @@ int load(Arguments& info) { std::cout << "Author: " << esm.getAuthor() << std::endl << "Description: " << esm.getDesc() << std::endl - << "File format version: " << esm.getFVer() << std::endl - << "Special flag: " << esm.getSpecial() << std::endl; + << "File format version: " << esm.getFVer() << std::endl; ESM::ESMReader::MasterList m = esm.getMasters(); if (!m.empty()) { diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index f5ddf62802..af83ad816a 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -21,17 +21,6 @@ enum FileType FT_ESS = 32 // Savegame }; -// Used to mark special files. The original ESM files are given -// special treatment in a few places, most noticably in loading and -// filtering out "dirtly" GMST entries correctly. -enum SpecialFile - { - SF_Other, - SF_Morrowind, - SF_Tribunal, - SF_Bloodmoon - }; - /* A structure used for holding fixed-length strings. In the case of LEN=4, it can be more efficient to match the string as a 32 bit number, therefore the struct is implemented as a union with an int. diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index edd047d92d..98c598eb9a 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -51,18 +51,6 @@ void ESMReader::openRaw(Ogre::DataStreamPtr _esm, const std::string &name) mEsm = _esm; mCtx.filename = name; mCtx.leftFile = mEsm->size(); - - // Flag certain files for special treatment, based on the file - // name. - const char *cstr = mCtx.filename.c_str(); - if (iends(cstr, "Morrowind.esm")) - mSpf = SF_Morrowind; - else if (iends(cstr, "Tribunal.esm")) - mSpf = SF_Tribunal; - else if (iends(cstr, "Bloodmoon.esm")) - mSpf = SF_Bloodmoon; - else - mSpf = SF_Other; } void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 94bf0f3d33..dd7809fb3c 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -38,7 +38,6 @@ public: int getVer() const { return mCtx.header.version; } float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - int getSpecial() const { return mSpf; } const std::string getAuthor() const { return mCtx.header.author.toString(); } const std::string getDesc() const { return mCtx.header.desc.toString(); } const MasterList &getMasters() const { return mMasters; } @@ -261,7 +260,6 @@ private: ESM_Context mCtx; // Special file signifier (see SpecialFile enum above) - int mSpf; // Buffer for ESM strings std::vector mBuffer; From b085c4f7492dcfad922e4ed8260142d0bef64d67 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 11 Mar 2013 16:53:42 +0100 Subject: [PATCH 0038/1537] removing more leftovers --- components/esm/esmcommon.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index af83ad816a..a8dfcf0bf7 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -14,13 +14,6 @@ enum Version VER_13 = 0x3fa66666 }; -enum FileType - { - FT_ESP = 0, // Plugin - FT_ESM = 1, // Master - FT_ESS = 32 // Savegame - }; - /* A structure used for holding fixed-length strings. In the case of LEN=4, it can be more efficient to match the string as a 32 bit number, therefore the struct is implemented as a union with an int. From 9e68a420ae5dc10e6e12ecf40ce8c99c600e33d5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 08:15:20 +0100 Subject: [PATCH 0039/1537] restructuring tes3 record structs --- apps/esmtool/esmtool.cpp | 6 +-- apps/openmw/mwworld/esmstore.cpp | 5 +- components/esm/esmcommon.hpp | 52 ++++++++++++------- components/esm/esmreader.cpp | 7 +-- components/esm/esmreader.hpp | 21 +++----- components/esm/esmwriter.cpp | 20 +++---- components/esm/esmwriter.hpp | 3 +- components/esm/loadcell.cpp | 4 +- .../fileorderlist/model/datafilesmodel.cpp | 12 ++--- 9 files changed, 69 insertions(+), 61 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 8d060cbd22..5cc1b6bcbb 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -23,7 +23,7 @@ struct ESMData std::string author; std::string description; int version; - ESM::ESMReader::MasterList masters; + std::vector masters; std::deque mRecords; std::map > mCellRefs; @@ -289,7 +289,7 @@ int load(Arguments& info) std::cout << "Author: " << esm.getAuthor() << std::endl << "Description: " << esm.getDesc() << std::endl << "File format version: " << esm.getFVer() << std::endl; - ESM::ESMReader::MasterList m = esm.getMasters(); + std::vector m = esm.getMasters(); if (!m.empty()) { std::cout << "Masters:" << std::endl; @@ -427,7 +427,7 @@ int clone(Arguments& info) esm.setDescription(info.data.description); esm.setVersion(info.data.version); - for (ESM::ESMReader::MasterList::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) + for (std::vector::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); std::fstream save(info.outname.c_str(), std::fstream::out | std::fstream::binary); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 257676076c..09a39ff8b1 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -27,14 +27,15 @@ void ESMStore::load(ESM::ESMReader &esm) ESM::Dialogue *dialogue = 0; + /// \todo Move this to somewhere else. ESMReader? // Cache parent esX files by tracking their indices in the global list of // all files/readers used by the engine. This will greaty accelerate // refnumber mangling, as required for handling moved references. int index = ~0; - const ESM::ESMReader::MasterList &masters = esm.getMasters(); + const std::vector &masters = esm.getMasters(); std::vector *allPlugins = esm.getGlobalReaderList(); for (size_t j = 0; j < masters.size(); j++) { - ESM::MasterData &mast = const_cast(masters[j]); + ESM::Header::MasterData &mast = const_cast(masters[j]); std::string fname = mast.name; for (int i = 0; i < esm.getIndex(); i++) { const std::string &candidate = allPlugins->at(i).getContext().filename; diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index a8dfcf0bf7..cbdd05a49a 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -2,6 +2,8 @@ #define OPENMW_ESM_COMMON_H #include +#include +#include #include #include @@ -43,6 +45,8 @@ union NAME_T bool operator!=(int v) const { return v != val; } std::string toString() const { return std::string(name, strnlen(name, LEN)); } + + void assign (const std::string& value) { std::strncpy (name, value.c_str(), LEN); } }; typedef NAME_T<4> NAME; @@ -53,27 +57,37 @@ typedef NAME_T<256> NAME256; #pragma pack(push) #pragma pack(1) /// File header data for all ES files -struct HEDRstruct +struct Header { - /* File format version. This is actually a float, the supported - versions are 1.2 and 1.3. These correspond to: - 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 - */ - int version; - int type; // 0=esp, 1=esm, 32=ess (unused) - NAME32 author; // Author's name - NAME256 desc; // File description - int records; // Number of records? Not used. -}; + struct Data + { + /* File format version. This is actually a float, the supported + versions are 1.2 and 1.3. These correspond to: + 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 + */ + int version; + int type; // 0=esp, 1=esm, 32=ess (unused) + NAME32 author; // Author's name + NAME256 desc; // File description + int records; // Number of records? Not used. + }; -// Defines another files (esm or esp) that this file depends upon. -struct MasterData -{ - std::string name; - uint64_t size; - int index; // Position of the parent file in the global list of loaded files -}; + // Defines another files (esm or esp) that this file depends upon. + struct MasterData + { + std::string name; + uint64_t size; + int index; // Position of the parent file in the global list of loaded files + }; + Data mData; + std::vector mMaster; +}; +#pragma pack(pop) + + +#pragma pack(push) +#pragma pack(1) // Data that is only present in save game files struct SaveData { @@ -95,7 +109,7 @@ struct ESM_Context uint32_t leftRec, leftSub; size_t leftFile; NAME recName, subName; - HEDRstruct header; + Header::Data header; // When working with multiple esX files, we will generate lists of all files that // actually contribute to a specific cell. Therefore, we need to store the index // of the file belonging to this contest. See CellStore::(list/load)refs for details. diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 98c598eb9a..70ab0caa38 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -63,16 +63,17 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getRecHeader(); // Get the header - getHNT(mCtx.header, "HEDR", 300); + getHNT (mHeader.mData, "HEDR", 300); + mCtx.header = mHeader.mData; // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. while (isNextSub("MAST")) { - MasterData m; + Header::MasterData m; m.name = getHString(); m.size = getHNLong("DATA"); - mMasters.push_back(m); + mHeader.mMaster.push_back(m); } } diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index dd7809fb3c..6850c7a148 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -22,25 +22,17 @@ public: ESMReader(void); - /************************************************************************* - * - * Public type definitions - * - *************************************************************************/ - - typedef std::vector MasterList; - /************************************************************************* * * Information retrieval * *************************************************************************/ - int getVer() const { return mCtx.header.version; } - float getFVer() const { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; } - const std::string getAuthor() const { return mCtx.header.author.toString(); } - const std::string getDesc() const { return mCtx.header.desc.toString(); } - const MasterList &getMasters() const { return mMasters; } + int getVer() const { return mHeader.mData.version; } + float getFVer() const { if(mHeader.mData.version == VER_12) return 1.2; else return 1.3; } + const std::string getAuthor() const { return mHeader.mData.author.toString(); } + const std::string getDesc() const { return mHeader.mData.desc.toString(); } + const std::vector &getMasters() const { return mHeader.mMaster; } const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } @@ -264,7 +256,8 @@ private: // Buffer for ESM strings std::vector mBuffer; - MasterList mMasters; + Header mHeader; + std::vector *mGlobalReaderList; ToUTF8::Utf8Encoder* mEncoder; }; diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index faceeeaa6f..6a3bfa9bdf 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -1,6 +1,5 @@ #include "esmwriter.hpp" #include -#include bool count = true; @@ -9,30 +8,30 @@ namespace ESM int ESMWriter::getVersion() { - return m_header.version; + return mHeader.mData.version; } void ESMWriter::setVersion(int ver) { - m_header.version = ver; + mHeader.mData.version = ver; } void ESMWriter::setAuthor(const std::string& auth) { - strncpy((char*)&m_header.author, auth.c_str(), 32); + mHeader.mData.author.assign (auth); } void ESMWriter::setDescription(const std::string& desc) { - strncpy((char*)&m_header.desc, desc.c_str(), 256); + mHeader.mData.desc.assign (desc); } void ESMWriter::addMaster(const std::string& name, uint64_t size) { - MasterData d; + Header::MasterData d; d.name = name; d.size = size; - m_masters.push_back(d); + mHeader.mMaster.push_back(d); } void ESMWriter::save(const std::string& file) @@ -48,11 +47,12 @@ void ESMWriter::save(std::ostream& file) startRecord("TES3", 0); - m_header.records = 0; - writeHNT("HEDR", m_header, 300); + mHeader.mData.records = 0; + writeHNT("HEDR", mHeader.mData, 300); m_headerPos = m_stream->tellp() - (std::streampos)4; - for (std::list::iterator it = m_masters.begin(); it != m_masters.end(); ++it) + for (std::vector::iterator it = mHeader.mMaster.begin(); + it != mHeader.mMaster.end(); ++it) { writeHNCString("MAST", it->name); writeHNT("DATA", it->size); diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index f488cce3e1..e8ff27577a 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -88,14 +88,13 @@ public: void write(const char* data, size_t size); private: - std::list m_masters; std::list m_records; std::ostream* m_stream; std::streampos m_headerPos; ToUTF8::Utf8Encoder* m_encoder; int m_recordCount; - HEDRstruct m_header; + Header mHeader; }; } diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 76a48e5ec4..da60f76af8 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -245,7 +245,7 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) // If the most significant 8 bits are used, then this reference already exists. // In this case, do not spawn a new reference, but overwrite the old one. ref.mRefnum &= 0x00ffffff; // delete old plugin ID - const ESM::ESMReader::MasterList &masters = esm.getMasters(); + const std::vector &masters = esm.getMasters(); global = masters[local-1].index + 1; ref.mRefnum |= global << 24; // insert global plugin ID } @@ -348,7 +348,7 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) int local = (mref.mRefnum & 0xff000000) >> 24; size_t global = esm.getIndex() + 1; mref.mRefnum &= 0x00ffffff; // delete old plugin ID - const ESM::ESMReader::MasterList &masters = esm.getMasters(); + const std::vector &masters = esm.getMasters(); global = masters[local-1].index + 1; mref.mRefnum |= global << 24; // insert global plugin ID diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index b33e2e12ab..71a320190c 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -157,7 +157,7 @@ Qt::ItemFlags DataFilesModel::flags(const QModelIndex &index) const if (!file) return Qt::NoItemFlags; - if (canBeChecked(file)) { + if (canBeChecked(file)) { if (index.column() == 0) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } else { @@ -226,7 +226,7 @@ bool lessThanEsmFile(const EsmFile *e1, const EsmFile *e2) return true; if (!e1->fileName().endsWith(".esm") && e2->fileName().endsWith(".esm")) return false; - + return e1->fileName().toLower() < e2->fileName().toLower(); } @@ -281,7 +281,7 @@ void DataFilesModel::addFiles(const QString &path) fileReader.setEncoder(&encoder); fileReader.open(dir.absoluteFilePath(path).toStdString()); - ESM::ESMReader::MasterList mlist = fileReader.getMasters(); + std::vector mlist = fileReader.getMasters(); QStringList masters; for (unsigned int i = 0; i < mlist.size(); ++i) { @@ -369,10 +369,10 @@ QStringList DataFilesModel::checkedItems() QStringList DataFilesModel::checkedItemsPaths() { QStringList list; - + QList::ConstIterator it; QList::ConstIterator itEnd = mFiles.constEnd(); - + int i = 0; for (it = mFiles.constBegin(); it != itEnd; ++it) { EsmFile *file = item(i); @@ -381,7 +381,7 @@ QStringList DataFilesModel::checkedItemsPaths() if (mCheckStates[file->fileName()] == Qt::Checked && canBeChecked(file)) list << file->path(); } - + return list; } From 731ac6a16084e86fef90bff7ca8a676eb652a279 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 08:30:51 +0100 Subject: [PATCH 0040/1537] removed redundant copy of Header::Data --- components/esm/esmcommon.hpp | 1 - components/esm/esmreader.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index cbdd05a49a..42fdc1211b 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -109,7 +109,6 @@ struct ESM_Context uint32_t leftRec, leftSub; size_t leftFile; NAME recName, subName; - Header::Data header; // When working with multiple esX files, we will generate lists of all files that // actually contribute to a specific cell. Therefore, we need to store the index // of the file belonging to this contest. See CellStore::(list/load)refs for details. diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 70ab0caa38..ea2bf76945 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -64,7 +64,6 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) // Get the header getHNT (mHeader.mData, "HEDR", 300); - mCtx.header = mHeader.mData; // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. From 16570ce87b021596e24b281b4e12c66f455e7896 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 09:16:03 +0100 Subject: [PATCH 0041/1537] moved header record struct to separate file --- components/CMakeLists.txt | 2 +- components/esm/esmcommon.hpp | 33 ----------------------- components/esm/esmreader.cpp | 13 +-------- components/esm/esmreader.hpp | 4 ++- components/esm/esmwriter.cpp | 18 +++---------- components/esm/esmwriter.hpp | 7 ++--- components/esm/loadtes3.cpp | 40 +++++++++++++++++++++++++++ components/esm/loadtes3.hpp | 52 ++++++++++++++++++++++++++++++++++++ 8 files changed, 105 insertions(+), 64 deletions(-) create mode 100644 components/esm/loadtes3.cpp create mode 100644 components/esm/loadtes3.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 38625fb529..f7b97056cb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist variant variantimp + loadweap records aipackage effectlist spelllist variant variantimp loadtes3 ) add_component_dir (misc diff --git a/components/esm/esmcommon.hpp b/components/esm/esmcommon.hpp index 42fdc1211b..6f51c767ec 100644 --- a/components/esm/esmcommon.hpp +++ b/components/esm/esmcommon.hpp @@ -2,7 +2,6 @@ #define OPENMW_ESM_COMMON_H #include -#include #include #include @@ -54,38 +53,6 @@ typedef NAME_T<32> NAME32; typedef NAME_T<64> NAME64; typedef NAME_T<256> NAME256; -#pragma pack(push) -#pragma pack(1) -/// File header data for all ES files -struct Header -{ - struct Data - { - /* File format version. This is actually a float, the supported - versions are 1.2 and 1.3. These correspond to: - 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 - */ - int version; - int type; // 0=esp, 1=esm, 32=ess (unused) - NAME32 author; // Author's name - NAME256 desc; // File description - int records; // Number of records? Not used. - }; - - // Defines another files (esm or esp) that this file depends upon. - struct MasterData - { - std::string name; - uint64_t size; - int index; // Position of the parent file in the global list of loaded files - }; - - Data mData; - std::vector mMaster; -}; -#pragma pack(pop) - - #pragma pack(push) #pragma pack(1) // Data that is only present in save game files diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index ea2bf76945..979088b801 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -62,18 +62,7 @@ void ESMReader::open(Ogre::DataStreamPtr _esm, const std::string &name) getRecHeader(); - // Get the header - getHNT (mHeader.mData, "HEDR", 300); - - // Some mods abuse the header.version field for the version of the mod instead of the version of the file format, so we can only ignore it. - - while (isNextSub("MAST")) - { - Header::MasterData m; - m.name = getHString(); - m.size = getHNLong("DATA"); - mHeader.mMaster.push_back(m); - } + mHeader.load (*this); } void ESMReader::open(const std::string &file) diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index 6850c7a148..e377470eeb 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -12,7 +12,9 @@ #include #include + #include "esmcommon.hpp" +#include "loadtes3.hpp" namespace ESM { @@ -20,7 +22,7 @@ class ESMReader { public: - ESMReader(void); + ESMReader(); /************************************************************************* * diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index 6a3bfa9bdf..edb681f329 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -1,5 +1,8 @@ #include "esmwriter.hpp" + +#include #include +#include bool count = true; @@ -47,26 +50,13 @@ void ESMWriter::save(std::ostream& file) startRecord("TES3", 0); - mHeader.mData.records = 0; - writeHNT("HEDR", mHeader.mData, 300); - m_headerPos = m_stream->tellp() - (std::streampos)4; - - for (std::vector::iterator it = mHeader.mMaster.begin(); - it != mHeader.mMaster.end(); ++it) - { - writeHNCString("MAST", it->name); - writeHNT("DATA", it->size); - } + mHeader.save (*this); endRecord("TES3"); } void ESMWriter::close() { - std::cout << "Writing amount of saved records (" << m_recordCount - 1 << ")" << std::endl; - m_stream->seekp(m_headerPos); - writeT(m_recordCount-1); - m_stream->seekp(0, std::ios::end); m_stream->flush(); if (!m_records.empty()) diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index e8ff27577a..b0e9329d4b 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -1,12 +1,13 @@ #ifndef OPENMW_ESM_WRITER_H #define OPENMW_ESM_WRITER_H -#include +#include #include -#include + +#include #include "esmcommon.hpp" -#include +#include "loadtes3.hpp" namespace ESM { diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp new file mode 100644 index 0000000000..64f1446f18 --- /dev/null +++ b/components/esm/loadtes3.cpp @@ -0,0 +1,40 @@ + +#include "loadtes3.hpp" + +#include "esmcommon.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" + +void ESM::Header::blank() +{ + mData.version = ESM::VER_13; + mData.type = 0; + mData.author.assign (""); + mData.desc.assign (""); + mData.records = 0; +} + +void ESM::Header::load (ESMReader &esm) +{ + esm.getHNT (mData, "HEDR", 300); + + while (esm.isNextSub ("MAST")) + { + MasterData m; + m.name = esm.getHString(); + m.size = esm.getHNLong ("DATA"); + mMaster.push_back (m); + } +} + +void ESM::Header::save (ESMWriter &esm) +{ + esm.writeHNT ("HEDR", mData, 300); + + for (std::vector::iterator iter = mMaster.begin(); + iter != mMaster.end(); ++iter) + { + esm.writeHNCString ("MAST", iter->name); + esm.writeHNT ("DATA", iter->size); + } +} \ No newline at end of file diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp new file mode 100644 index 0000000000..c0b1e3af77 --- /dev/null +++ b/components/esm/loadtes3.hpp @@ -0,0 +1,52 @@ +#ifndef COMPONENT_ESM_TES3_H +#define COMPONENT_ESM_TES3_H + +#include + +#include "esmcommon.hpp" + +namespace ESM +{ + class ESMReader; + class ESMWriter; + +#pragma pack(push) +#pragma pack(1) + + /// \brief File header record + struct Header + { + struct Data + { + /* File format version. This is actually a float, the supported + versions are 1.2 and 1.3. These correspond to: + 1.2 = 0x3f99999a and 1.3 = 0x3fa66666 + */ + int version; + int type; // 0=esp, 1=esm, 32=ess (unused) + NAME32 author; // Author's name + NAME256 desc; // File description + int records; // Number of records? Not used. + }; + + // Defines another files (esm or esp) that this file depends upon. + struct MasterData + { + std::string name; + uint64_t size; + int index; // Position of the parent file in the global list of loaded files + }; + + Data mData; + std::vector mMaster; + + void blank(); + + void load (ESMReader &esm); + void save (ESMWriter &esm); + }; +#pragma pack(pop) + +} + +#endif \ No newline at end of file From 50abb221625625ae6b448b65ccf74626f3f61437 Mon Sep 17 00:00:00 2001 From: graffy76 Date: Tue, 12 Mar 2013 06:28:13 -0500 Subject: [PATCH 0042/1537] Fix to allow application closing from multiple views and a single view. --- apps/opencs/model/doc/document.cpp | 7 +- apps/opencs/model/doc/document.hpp | 3 +- apps/opencs/view/doc/view.cpp | 10 ++- apps/opencs/view/doc/view.hpp | 6 +- apps/opencs/view/doc/viewmanager.cpp | 89 ++++++++++--------- apps/opencs/view/doc/viewmanager.hpp | 11 ++- .../fileorderlist/model/datafilesmodel.cpp | 2 +- 7 files changed, 76 insertions(+), 52 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 3d8f961121..af34aeedf4 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,7 @@ #include "document.hpp" #include - +#include void CSMDoc::Document::load (const std::vector::const_iterator& begin, const std::vector::const_iterator& end, bool lastAsModified) { @@ -237,6 +237,11 @@ CSMDoc::Document::Document (const std::vector& files, b connect (&mSaveTimer, SIGNAL(timeout()), this, SLOT (saving())); } +CSMDoc::Document::~Document() +{ + qDebug() << "document destroyed"; +} + QUndoStack& CSMDoc::Document::getUndoStack() { return mUndoStack; diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index a7b198689e..94d5fe85cc 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -63,6 +63,7 @@ namespace CSMDoc public: Document (const std::vector& files, bool new_); + ~Document(); QUndoStack& getUndoStack(); @@ -105,4 +106,4 @@ namespace CSMDoc }; } -#endif \ No newline at end of file +#endif diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfbd92a609..995d3ca2e2 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -46,7 +46,8 @@ void CSVDoc::View::setupFileMenu() file->addAction(close); QAction *exit = new QAction (tr ("&Exit"), this); - connect (exit, SIGNAL (triggered()), QApplication::instance(), SLOT (closeAllWindows())); + connect (exit, SIGNAL (triggered()), this, SLOT (exit())); + connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *))); file->addAction(exit); } @@ -131,8 +132,6 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), mViewTotal (totalViews) { - // setDockOptions (QMainWindow::AllowNestedDocks); - resize (300, 300); /// \todo get default size from settings and set reasonable minimal size mSubViewWindow.setDockOptions (QMainWindow::AllowNestedDocks); @@ -255,3 +254,8 @@ CSVDoc::Operations *CSVDoc::View::getOperations() const { return mOperations; } + +void CSVDoc::View::exit() +{ + emit exitApplicationRequest (this); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 92c57fe9ec..e91a4d4a80 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -66,6 +66,8 @@ namespace CSVDoc void updateActions(); + void exitApplication(); + public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); @@ -92,7 +94,7 @@ namespace CSVDoc void loadDocumentRequest(); - void closeAllViews (View *); + void exitApplicationRequest (CSVDoc::View *view); public slots: @@ -106,6 +108,8 @@ namespace CSVDoc void save(); + void exit(); + void verify(); void addGlobalsSubView(); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 83ace49387..527e3b2044 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -36,7 +36,7 @@ void CSVDoc::ViewManager::updateIndices() } CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) - : mDocumentManager (documentManager), mCloseMeOnSaveStateChange(0), mUserWarned(false) + : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; @@ -45,16 +45,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); - - connect (this, SIGNAL (exitApplication()), QApplication::instance(), SLOT (closeAllWindows())); - } CSVDoc::ViewManager::~ViewManager() { delete mDelegateFactories; - //not needed due to deletion in ViewManager::closeRequest? for (std::vector::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter) delete *iter; } @@ -112,32 +108,40 @@ bool CSVDoc::ViewManager::closeRequest (View *view) CSMDoc::Document *document = view->getDocument(); - //notify user of saving in progress - if ( (document->getState() & CSMDoc::State_Saving) ) - continueWithClose = showSaveInProgressMessageBox (iter); - - //notify user of unsaved changes and process response - else if ( document->getState() & CSMDoc::State_Modified) - continueWithClose = showModifiedDocumentMessageBox (iter); - - if (continueWithClose) + if (last) + continueWithClose = notifySaveOnClose (view); + else { (*iter)->deleteLater(); mViews.erase (iter); - if (last) - mDocumentManager.removeDocument (document); - else - updateIndices(); + updateIndices(); } } return continueWithClose; } -bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::iterator viewIter) +bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view) +{ + bool result = true; + CSMDoc::Document *document = view->getDocument(); + + //notify user of saving in progress + if ( (document->getState() & CSMDoc::State_Saving) ) + result = showSaveInProgressMessageBox (view); + + //notify user of unsaved changes and process response + else if ( document->getState() & CSMDoc::State_Modified) + result = showModifiedDocumentMessageBox (view); + + return result; +} + +bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view) { QMessageBox messageBox; + CSMDoc::Document *document = view->getDocument(); messageBox.setText ("The document has been modified."); messageBox.setInformativeText ("Do you want to save your changes?"); @@ -147,31 +151,31 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i bool retVal = true; connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + + connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + mUserWarned = true; - int response = messageBox.exec(); - mUserWarned = false; switch (response) { case QMessageBox::Save: - (*viewIter)->getDocument()->save(); - mCloseMeOnSaveStateChange = viewIter; + document->save(); + mExitOnSaveStateChange = true; retVal = false; break; case QMessageBox::Discard: - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); break; case QMessageBox::Cancel: //disconnect to prevent unintended view closures - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; break; @@ -183,9 +187,10 @@ bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (std::vector::i return retVal; } -bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::iterator viewIter) +bool CSVDoc::ViewManager::showSaveInProgressMessageBox (CSVDoc::View *view) { QMessageBox messageBox; + CSMDoc::Document *document = view->getDocument(); messageBox.setText ("The document is currently being saved."); messageBox.setInformativeText("Do you want to close now and abort saving, or wait until saving has completed?"); @@ -199,38 +204,37 @@ bool CSVDoc::ViewManager::showSaveInProgressMessageBox (std::vector::ite bool retVal = true; //Connections shut down message box if operation ends before user makes a decision. - connect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + connect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); connect (this, SIGNAL (closeMessageBox()), &messageBox, SLOT (close())); //set / clear the user warned flag to indicate whether or not the message box is currently active. mUserWarned = true; - messageBox.exec(); - mUserWarned = false; //if closed by the warning handler, defaults to the RejectRole button (closeButton) if (messageBox.clickedButton() == waitButton) { //save the View iterator for shutdown after the save operation ends - mCloseMeOnSaveStateChange = viewIter; + mExitOnSaveStateChange = true; retVal = false; } else if (messageBox.clickedButton() == closeButton) { //disconnect to avoid segmentation fault - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); - (*viewIter)->abortOperation(CSMDoc::State_Saving); - mCloseMeOnSaveStateChange = mViews.end(); + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + + view->abortOperation(CSMDoc::State_Saving); + mExitOnSaveStateChange = true; } else if (messageBox.clickedButton() == cancelButton) { //abort shutdown, allow save to complete //disconnection to prevent unintended view closures - mCloseMeOnSaveStateChange = mViews.end(); - disconnect ((*viewIter)->getDocument(), SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); + mExitOnSaveStateChange = false; + disconnect (document, SIGNAL (stateChanged (int, CSMDoc::Document *)), this, SLOT (onExitWarningHandler(int, CSMDoc::Document *))); retVal = false; } @@ -262,10 +266,13 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc //otherwise, the user has closed the message box before the save operation ended. //exit the application - else if (mCloseMeOnSaveStateChange!=mViews.end()) - { - emit exitApplication(); - mCloseMeOnSaveStateChange = mViews.end(); - } + else if (mExitOnSaveStateChange) + QApplication::instance()->exit(); } } + +void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view) +{ + if (notifySaveOnClose (view)) + QApplication::instance()->exit(); +} diff --git a/apps/opencs/view/doc/viewmanager.hpp b/apps/opencs/view/doc/viewmanager.hpp index b77e5f5758..90f23eaa11 100644 --- a/apps/opencs/view/doc/viewmanager.hpp +++ b/apps/opencs/view/doc/viewmanager.hpp @@ -27,7 +27,7 @@ namespace CSVDoc CSMDoc::DocumentManager& mDocumentManager; std::vector mViews; CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories; - std::vector::iterator mCloseMeOnSaveStateChange; + bool mExitOnSaveStateChange; bool mUserWarned; // not implemented @@ -35,8 +35,9 @@ namespace CSVDoc ViewManager& operator= (const ViewManager&); void updateIndices(); - bool showModifiedDocumentMessageBox (std::vector::iterator view); - bool showSaveInProgressMessageBox (std::vector::iterator view); + bool notifySaveOnClose (View *view = 0); + bool showModifiedDocumentMessageBox (View *view); + bool showSaveInProgressMessageBox (View *view); public: @@ -60,7 +61,9 @@ namespace CSVDoc void closeMessageBox(); - void exitApplication(); + public slots: + + void exitApplication (CSVDoc::View *view); private slots: diff --git a/components/fileorderlist/model/datafilesmodel.cpp b/components/fileorderlist/model/datafilesmodel.cpp index b33e2e12ab..25286e2f85 100644 --- a/components/fileorderlist/model/datafilesmodel.cpp +++ b/components/fileorderlist/model/datafilesmodel.cpp @@ -1,6 +1,6 @@ -#include #include #include +#include #include From 75bd30844db2ce8a5e3d1e1e9ea9b12f0bc5854a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 14:33:35 +0100 Subject: [PATCH 0043/1537] added optional format sub-record to tes3 record --- apps/esmtool/esmtool.cpp | 1 + components/esm/esmreader.cpp | 7 ++++++- components/esm/esmreader.hpp | 1 + components/esm/esmwriter.cpp | 10 ++++++++++ components/esm/esmwriter.hpp | 2 ++ components/esm/loadtes3.cpp | 13 +++++++++++++ components/esm/loadtes3.hpp | 3 +++ 7 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 5cc1b6bcbb..20c01af259 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -426,6 +426,7 @@ int clone(Arguments& info) esm.setAuthor(info.data.author); esm.setDescription(info.data.description); esm.setVersion(info.data.version); + esm.setRecordCount (recordCount); for (std::vector::iterator it = info.data.masters.begin(); it != info.data.masters.end(); ++it) esm.addMaster(it->name, it->size); diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp index 979088b801..580e576d05 100644 --- a/components/esm/esmreader.cpp +++ b/components/esm/esmreader.cpp @@ -15,11 +15,16 @@ ESM_Context ESMReader::getContext() return mCtx; } -ESMReader::ESMReader(void): +ESMReader::ESMReader(): mBuffer(50*1024) { } +int ESMReader::getFormat() const +{ + return mHeader.mFormat; +} + void ESMReader::restoreContext(const ESM_Context &rc) { // Reopen the file if necessary diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp index e377470eeb..f805998e43 100644 --- a/components/esm/esmreader.hpp +++ b/components/esm/esmreader.hpp @@ -35,6 +35,7 @@ public: const std::string getAuthor() const { return mHeader.mData.author.toString(); } const std::string getDesc() const { return mHeader.mData.desc.toString(); } const std::vector &getMasters() const { return mHeader.mMaster; } + int getFormat() const; const NAME &retSubName() const { return mCtx.subName; } uint32_t getSubSize() const { return mCtx.leftSub; } diff --git a/components/esm/esmwriter.cpp b/components/esm/esmwriter.cpp index edb681f329..3ea6bd350a 100644 --- a/components/esm/esmwriter.cpp +++ b/components/esm/esmwriter.cpp @@ -29,6 +29,16 @@ void ESMWriter::setDescription(const std::string& desc) mHeader.mData.desc.assign (desc); } +void ESMWriter::setRecordCount (int count) +{ + mHeader.mData.records = count; +} + +void ESMWriter::setFormat (int format) +{ + mHeader.mFormat = format; +} + void ESMWriter::addMaster(const std::string& name, uint64_t size) { Header::MasterData d; diff --git a/components/esm/esmwriter.hpp b/components/esm/esmwriter.hpp index b0e9329d4b..be3ae33abe 100644 --- a/components/esm/esmwriter.hpp +++ b/components/esm/esmwriter.hpp @@ -26,6 +26,8 @@ public: void setEncoder(ToUTF8::Utf8Encoder *encoding); // Write strings as UTF-8? void setAuthor(const std::string& author); void setDescription(const std::string& desc); + void setRecordCount (int count); + void setFormat (int format); void addMaster(const std::string& name, uint64_t size); diff --git a/components/esm/loadtes3.cpp b/components/esm/loadtes3.cpp index 64f1446f18..74d578ba7d 100644 --- a/components/esm/loadtes3.cpp +++ b/components/esm/loadtes3.cpp @@ -12,12 +12,22 @@ void ESM::Header::blank() mData.author.assign (""); mData.desc.assign (""); mData.records = 0; + mFormat = CurrentFormat; } void ESM::Header::load (ESMReader &esm) { esm.getHNT (mData, "HEDR", 300); + if (esm.isNextSub ("FORM")) + { + esm.getHT (mFormat); + if (mFormat<0) + esm.fail ("invalid format code"); + } + else + mFormat = 0; + while (esm.isNextSub ("MAST")) { MasterData m; @@ -31,6 +41,9 @@ void ESM::Header::save (ESMWriter &esm) { esm.writeHNT ("HEDR", mData, 300); + if (mFormat>0) + esm.writeHNT ("FORM", mFormat); + for (std::vector::iterator iter = mMaster.begin(); iter != mMaster.end(); ++iter) { diff --git a/components/esm/loadtes3.hpp b/components/esm/loadtes3.hpp index c0b1e3af77..b73a4c31e4 100644 --- a/components/esm/loadtes3.hpp +++ b/components/esm/loadtes3.hpp @@ -16,6 +16,8 @@ namespace ESM /// \brief File header record struct Header { + static const int CurrentFormat = 0; // most recent known format + struct Data { /* File format version. This is actually a float, the supported @@ -38,6 +40,7 @@ namespace ESM }; Data mData; + int mFormat; std::vector mMaster; void blank(); From 10fad47a8129837973e0e3d88cf94f15626c58c0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 12 Mar 2013 14:51:16 +0100 Subject: [PATCH 0044/1537] some cleanup --- apps/opencs/model/doc/document.cpp | 4 +--- apps/opencs/view/doc/viewmanager.cpp | 5 ----- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index af34aeedf4..7a88335c89 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -238,9 +238,7 @@ CSMDoc::Document::Document (const std::vector& files, b } CSMDoc::Document::~Document() -{ - qDebug() << "document destroyed"; -} +{} QUndoStack& CSMDoc::Document::getUndoStack() { diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 527e3b2044..33300f67a7 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -103,11 +103,6 @@ bool CSVDoc::ViewManager::closeRequest (View *view) { bool last = countViews (view->getDocument())<=1; - /// \todo check if save is in progress -> warn user about possible data loss - /// \todo check if document has not been saved -> return false and start close dialogue - - CSMDoc::Document *document = view->getDocument(); - if (last) continueWithClose = notifySaveOnClose (view); else From 4c588cbab616115b30f368bd7e018a3f984066d4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 12 Mar 2013 17:18:47 +0100 Subject: [PATCH 0045/1537] Levelup dialog is now dynamic; added level descriptions --- apps/openmw/mwgui/levelupdialog.cpp | 24 +++++++++++---- apps/openmw/mwgui/levelupdialog.hpp | 3 ++ apps/openmw/mwgui/widgets.cpp | 29 ++++++++++++++++++ apps/openmw/mwgui/widgets.hpp | 13 ++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 1 + files/mygui/openmw_levelup_dialog.layout | 38 +++++++++++++++++++----- 6 files changed, 96 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 45890b89fe..9473f48b4e 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -23,6 +23,8 @@ namespace MWGui getWidget(mOkButton, "OkButton"); getWidget(mClassImage, "ClassImage"); getWidget(mLevelText, "LevelText"); + getWidget(mLevelDescription, "LevelDescription"); + getWidget(mCoinBox, "Coins"); mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked); @@ -80,11 +82,13 @@ namespace MWGui void LevelupDialog::resetCoins () { - int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5; + int curX = 0; for (int i=0; i<3; ++i) { MyGUI::ImageBox* image = mCoins[i]; - image->setCoord(MyGUI::IntCoord(curX,250,16,16)); + image->detachFromWidget(); + image->attachToWidget(mCoinBox); + image->setCoord(MyGUI::IntCoord(curX,0,16,16)); curX += 24+2; } } @@ -95,6 +99,9 @@ namespace MWGui for (unsigned int i=0; idetachFromWidget(); + image->attachToWidget(mMainWidget); + int attribute = mSpentAttributes[i]; int xdiff = mAttributeMultipliers[attribute]->getCaption() == "" ? 0 : 30; @@ -113,8 +120,6 @@ namespace MWGui MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); - center(); - mSpentAttributes.clear(); resetCoins(); @@ -128,16 +133,25 @@ namespace MWGui mClassImage->setImageTexture ("textures\\levelup\\" + cls->mId + ".dds"); - /// \todo replace this with INI-imported texts int level = creatureStats.getLevel ()+1; mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast(level)); + std::string levelupdescription; + if(level>20) + levelupdescription=world->getFallback("Level_Up_Default"); + else + levelupdescription=world->getFallback("Level_Up_Level"+boost::lexical_cast(level)); + + mLevelDescription->setCaption (levelupdescription); + for (int i=0; i<8; ++i) { MyGUI::TextBox* text = mAttributeMultipliers[i]; int mult = pcStats.getLevelupAttributeMultiplier (i); text->setCaption(mult <= 1 ? "" : "x" + boost::lexical_cast(mult)); } + + center(); } void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index f5b24530d1..3c8b74800b 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -17,6 +17,9 @@ namespace MWGui MyGUI::Button* mOkButton; MyGUI::ImageBox* mClassImage; MyGUI::TextBox* mLevelText; + MyGUI::EditBox* mLevelDescription; + + MyGUI::Widget* mCoinBox; std::vector mAttributes; std::vector mAttributeValues; diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 506b906982..b0f7e6293b 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -586,6 +586,30 @@ void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::s } } +MyGUI::IntSize AutoSizedEditBox::getRequestedSize() +{ + return MyGUI::IntSize(getSize().width, getTextSize().height); +} + +void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) +{ + EditBox::setCaption(_value); + + notifySizeChange (this); +} + +void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) +{ + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + EditBox::setPropertyOverride (_key, _value); + } +} + MyGUI::IntSize AutoSizedButton::getRequestedSize() { @@ -660,6 +684,8 @@ void HBox::align () { sizes.push_back (std::make_pair(w->getSize(), hstretch)); total_width += w->getSize().width; + if (!(w->getUserString("VStretch") == "true")) + total_height = std::max(total_height, w->getSize().height); } if (i != count-1) @@ -783,6 +809,9 @@ void VBox::align () { sizes.push_back (std::make_pair(w->getSize(), vstretch)); total_height += w->getSize().height; + + if (!(w->getUserString("HStretch") == "true")) + total_width = std::max(total_width, w->getSize().width); } if (i != count-1) diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 597bcbe324..d2bcb69257 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace MyGUI { @@ -340,6 +341,18 @@ namespace MWGui virtual void setPropertyOverride(const std::string& _key, const std::string& _value); }; + class AutoSizedEditBox : public AutoSizedWidget, public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED( AutoSizedEditBox ) + + public: + virtual MyGUI::IntSize getRequestedSize(); + virtual void setCaption(const MyGUI::UString& _value); + + protected: + virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + }; + class AutoSizedButton : public AutoSizedWidget, public MyGUI::Button { MYGUI_RTTI_DERIVED( AutoSizedButton ) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 0e4c3a6082..3da739e260 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -129,6 +129,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"); diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout index 86e65e99a9..765bf88a83 100644 --- a/files/mygui/openmw_levelup_dialog.layout +++ b/files/mygui/openmw_levelup_dialog.layout @@ -1,17 +1,36 @@ - + + + + + + - + - + + + + + + + + + + + + + + + @@ -127,12 +146,17 @@ - - - - + + + + + + + + + From f943580138209a27497e0613ab6914f5194a3589 Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 12 Mar 2013 17:44:22 +0000 Subject: [PATCH 0046/1537] Somehow manages to get from one cell to another, but this looks wrong... And I don't know how morrowind do it, because aitravel is completly buggy --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++++- apps/openmw/mwmechanics/aitravel.hpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 09b0efad9c..3c2e29743a 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -169,9 +169,13 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + if(cellChange) std::cout << "cellChanged! \n"; //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; float yCell = 0; if (actor.getCell()->mCell->isExterior()) diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index a596f4c85d..3d220cb7e3 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -23,6 +23,9 @@ namespace MWMechanics float mY; float mZ; + int cellX; + int cellY; + bool isPathConstructed; std::list mPath; From fdcbdbf35df7f3401b5db0dd990927e1479387eb Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Mar 2013 19:44:34 +0100 Subject: [PATCH 0047/1537] Rewrote layout tooltips to use the new box layout system, fixes word wrapping delay --- apps/openmw/mwgui/tooltips.cpp | 68 ++++------- apps/openmw/mwgui/widgets.cpp | 2 + files/mygui/openmw_tooltips.layout | 179 ++++++++++++++--------------- 3 files changed, 112 insertions(+), 137 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8dcf398ca5..8eb0336a79 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -44,6 +44,11 @@ ToolTips::ToolTips(MWBase::WindowManager* windowManager) : mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); mRemainingDelay = mDelay; + + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } } void ToolTips::setEnabled(bool enabled) @@ -115,7 +120,7 @@ void ToolTips::onFrame(float frameDuration) } else { - mHorizontalScrollIndex = 0; + mHorizontalScrollIndex = 0; mRemainingDelay = mDelay; } mLastMouseX = mousePos.left; @@ -215,14 +220,6 @@ void ToolTips::onFrame(float frameDuration) 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); - } - else - tooltipSize = tooltip->getSize(); std::map userStrings = focus->getUserStrings(); for (std::map::iterator it = userStrings.begin(); @@ -243,32 +240,8 @@ void ToolTips::onFrame(float frameDuration) w->setProperty(propertyKey, it->second); } - for (unsigned int i=0; igetChildCount(); ++i) - { - MyGUI::Widget* w = tooltip->getChildAt(i); + tooltipSize = tooltip->getSize(); - 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 @@ -509,20 +482,21 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) captionSize.height); //if its too long we do hscroll with the caption - if (captionSize.width > maximumWidth){ - mHorizontalScrollIndex = mHorizontalScrollIndex + 2; - if (mHorizontalScrollIndex > captionSize.width){ - mHorizontalScrollIndex = -totalSize.width; - } - int horizontal_scroll = mHorizontalScrollIndex; - if (horizontal_scroll < 40){ - horizontal_scroll = 40; - }else{ - horizontal_scroll = 80 - mHorizontalScrollIndex; - } - captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + if (captionSize.width > maximumWidth) + { + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); } else { - captionWidget->setPosition (captionWidget->getPosition() + padding); + 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 diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index b0f7e6293b..2590990172 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -588,6 +588,8 @@ void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::s MyGUI::IntSize AutoSizedEditBox::getRequestedSize() { + if (getAlign().isHStretch()) + throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); return MyGUI::IntSize(getSize().width, getTextSize().height); } diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index 514d1a25b3..f554e2b0d5 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -5,124 +5,124 @@ - - - + + + - + - - - - + + + - + - - + - - - - + + + - + - - + - - - + - - - + + + - + + + + + + + - + - - - - + + + - + + + - - - + + + - + - - - - + + + - + + + - - - + + + + + + + + + - - - - - - + - - - - + @@ -135,37 +135,36 @@ - - + + + - + + - - - + + + + + + + + + + + - - - - - - + - - - - - - @@ -181,43 +180,43 @@ - - + + + - + - - - - + + + - + + - - - + + + + + + + + + - - - - - - + - - From c4a42f2e1f6edffe6d6610f64df2ad773f30a8a6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 13 Mar 2013 23:17:25 +0100 Subject: [PATCH 0048/1537] Fix infinite recursion on shutdown caused by incorrect onWidgetDestroy listener --- apps/openmw/mwgui/widgets.cpp | 10 ---------- apps/openmw/mwgui/widgets.hpp | 2 -- 2 files changed, 12 deletions(-) diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 2590990172..e822e047ea 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -749,11 +749,6 @@ void HBox::onWidgetCreated(MyGUI::Widget* _widget) align(); } -void HBox::onWidgetDestroy(MyGUI::Widget* _widget) -{ - align(); -} - MyGUI::IntSize HBox::getRequestedSize () { MyGUI::IntSize size(0,0); @@ -905,8 +900,3 @@ void VBox::onWidgetCreated(MyGUI::Widget* _widget) { align(); } - -void VBox::onWidgetDestroy(MyGUI::Widget* _widget) -{ - align(); -} diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index d2bcb69257..784537c42a 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -403,7 +403,6 @@ namespace MWGui virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onWidgetCreated(MyGUI::Widget* _widget); - virtual void onWidgetDestroy(MyGUI::Widget* _widget); }; class VBox : public Box, public MyGUI::Widget @@ -421,7 +420,6 @@ namespace MWGui virtual void setPropertyOverride(const std::string& _key, const std::string& _value); virtual void onWidgetCreated(MyGUI::Widget* _widget); - virtual void onWidgetDestroy(MyGUI::Widget* _widget); }; } } From 84afd873211f396d0e036824a50f788f4d20e445 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 03:04:02 +0100 Subject: [PATCH 0049/1537] Placeable objects should not collide unless they have a NiRootCollisionNode --- 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/mwworld/physicssystem.cpp | 16 +++++++++++----- apps/openmw/mwworld/physicssystem.hpp | 2 +- components/nifbullet/bulletnifloader.cpp | 16 ++++++++-------- components/nifbullet/bulletnifloader.hpp | 2 +- libs/openengine/bullet/BulletShapeLoader.cpp | 2 +- libs/openengine/bullet/BulletShapeLoader.h | 6 ++++-- libs/openengine/bullet/physic.cpp | 7 ++++++- libs/openengine/bullet/physic.hpp | 3 ++- 20 files changed, 46 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 2c561eb858..851a5ae360 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -35,7 +35,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Apparatus::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 654cb87fd6..fdf211c28a 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -38,7 +38,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Armor::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 6c3b7b86c3..4e29fa6845 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -33,7 +33,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Book::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 892ac091ce..dfced6daa8 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Clothing::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index bbba45df58..14cf6ff6f9 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -46,7 +46,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Ingredient::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 200f6e2d4a..7466657725 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -50,7 +50,7 @@ namespace MWClass const std::string &model = ref->mBase->mModel; if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,ref->mBase->mData.mFlags & ESM::Light::Carry); if (!ref->mBase->mSound.empty()) MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_Loop); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 7e909437cf..665644736d 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index d43a44359f..07e41bcfa6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -39,7 +39,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Miscellaneous::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 0ac78a2e40..37461ed905 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -38,7 +38,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Potion::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index a28be17e7e..5b1b55bd31 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Probe::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 39a7f65e07..d6afe93198 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -34,7 +34,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Repair::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index d8c11558cc..475c08ccbf 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -36,7 +36,7 @@ namespace MWClass { const std::string model = getModel(ptr); if(!model.empty()) - physics.addObject(ptr); + physics.addObject(ptr,true); } std::string Weapon::getModel(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 7edd202935..28f3317065 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -364,14 +364,15 @@ namespace MWWorld mEngine->removeHeightField(x, y); } - void PhysicsSystem::addObject (const Ptr& ptr) + void PhysicsSystem::addObject (const Ptr& ptr, bool placeable) { std::string mesh = MWWorld::Class::get(ptr).getModel(ptr); Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); handleToMesh[node->getName()] = mesh; - OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation()); - OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody - (mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true); + OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody( + mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, false, placeable); + OEngine::Physic::RigidBody* raycastingBody = mEngine->createAndAdjustRigidBody( + mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true, placeable); mEngine->addRigidBody(body, true, raycastingBody); } @@ -440,8 +441,13 @@ namespace MWWorld const std::string &handle = node->getName(); if(handleToMesh.find(handle) != handleToMesh.end()) { + bool placeable = false; + if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,true)) + placeable = body->mPlaceable; + else if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle,false)) + placeable = body->mPlaceable; removeObject(handle); - addObject(ptr); + addObject(ptr, placeable); } if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 60c8246ae3..2e48be4079 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -29,7 +29,7 @@ namespace MWWorld PhysicsSystem (OEngine::Render::OgreRenderer &_rend); ~PhysicsSystem (); - void addObject (const MWWorld::Ptr& ptr); + void addObject (const MWWorld::Ptr& ptr, bool placeable=false); void addActor (const MWWorld::Ptr& ptr); diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index af1243346a..04ac3d1410 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -109,17 +109,17 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) return; } - bool hasCollisionNode = hasRootCollisionNode(node); + cShape->mHasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(mesh1, node,0,hasCollisionNode,false,false); + handleNode(mesh1, node,0,false,false); if(mBoundingBox != NULL) { cShape->mCollisionShape = mBoundingBox; delete mesh1; } - else if (mHasShape && !cShape->mIgnore && cShape->mCollide) + else if (mHasShape && cShape->mCollide) { cShape->mCollisionShape = new TriangleMeshShape(mesh1,true); } @@ -136,14 +136,14 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) btTriangleMesh* mesh2 = new btTriangleMesh(); - handleNode(mesh2, node,0,hasCollisionNode,true,true); + handleNode(mesh2, node,0,true,true); if(mBoundingBox != NULL) { cShape->mRaycastingShape = mBoundingBox; delete mesh2; } - else if (mHasShape && !cShape->mIgnore) + else if (mHasShape) { cShape->mRaycastingShape = new TriangleMeshShape(mesh2,true); } @@ -174,7 +174,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) } void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, - bool hasCollisionNode, bool isCollisionNode, + bool isCollisionNode, bool raycasting) { // Accumulate the flags from all the child nodes. This works for all @@ -223,7 +223,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * } } - if (isCollisionNode || (!hasCollisionNode && !raycasting)) + if (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) { if(node->hasBounds) { @@ -246,7 +246,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(mesh, list[i].getPtr(), flags, hasCollisionNode, isCollisionNode, raycasting); + handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index 9cb5a3e86e..c231b75b68 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -82,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool hasCollisionNode, bool isCollisionNode, bool raycasting); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting); /** *Helper function diff --git a/libs/openengine/bullet/BulletShapeLoader.cpp b/libs/openengine/bullet/BulletShapeLoader.cpp index 8744c4e4d6..431d2b91b4 100644 --- a/libs/openengine/bullet/BulletShapeLoader.cpp +++ b/libs/openengine/bullet/BulletShapeLoader.cpp @@ -19,8 +19,8 @@ Ogre::Resource(creator, name, handle, group, isManual, loader) */ mCollisionShape = NULL; mRaycastingShape = NULL; + mHasCollisionNode = false; mCollide = true; - mIgnore = false; createParamDictionary("BulletShape"); } diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index fa03b02766..a6591010ad 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -35,12 +35,14 @@ public: btCollisionShape* mCollisionShape; btCollisionShape* mRaycastingShape; + // Whether or not a NiRootCollisionNode was present in the .nif. If there is none, the collision behaviour + // depends on object type, so we need to expose this variable. + bool mHasCollisionNode; + Ogre::Vector3 mBoxTranslation; Ogre::Quaternion mBoxRotation; //this flag indicate if the shape is used for collision or if it's for raycasting only. bool mCollide; - - bool mIgnore; }; /** diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index c4947af1e1..6e6490a411 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -144,6 +144,7 @@ namespace Physic RigidBody::RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name) : btRigidBody(CI) , mName(name) + , mPlaceable(false) { } @@ -368,7 +369,7 @@ namespace Physic RigidBody* PhysicEngine::createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting) + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation, bool raycasting, bool placeable) { std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; @@ -378,6 +379,9 @@ namespace Physic BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + if (placeable && !raycasting && shape->mCollisionShape && !shape->mHasCollisionNode) + return NULL; + if (!shape->mCollisionShape && !raycasting) return NULL; if (!shape->mRaycastingShape && raycasting) @@ -395,6 +399,7 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo (0,newMotionState, raycasting ? shape->mRaycastingShape : shape->mCollisionShape); RigidBody* body = new RigidBody(CI,name); + body->mPlaceable = placeable; if(scaledBoxTranslation != 0) *scaledBoxTranslation = shape->mBoxTranslation * scale; diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 367db261fd..6ce4edba35 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -164,6 +164,7 @@ namespace Physic RigidBody(btRigidBody::btRigidBodyConstructionInfo& CI,std::string name); virtual ~RigidBody(); std::string mName; + bool mPlaceable; }; struct HeightField @@ -197,7 +198,7 @@ namespace Physic */ RigidBody* createAndAdjustRigidBody(const std::string &mesh, const std::string &name, float scale, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, - Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false); + Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0, bool raycasting=false, bool placeable=false); /** * Adjusts a rigid body to the right position and rotation From 80804fac351fedcde4735753c7ae2db461a80628 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 17:16:37 +0000 Subject: [PATCH 0050/1537] check if the NPC is close from a non loaded cell. If yes, AITravel is simply ended. --- apps/openmw/mwmechanics/aitravel.cpp | 31 +++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 3c2e29743a..57b9f66dde 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -7,6 +7,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "movement.hpp" +#include "../mwworld/player.hpp" #include #include @@ -167,13 +168,35 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - if(cellChange) std::cout << "cellChanged! \n"; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -190,7 +213,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); mPath = getPath(start,end,graph); - if(mPath.empty()) std::cout << "graph doesn't find any way..."; + ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; @@ -200,7 +223,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(mPath.empty()) { - std::cout << "pathc empty"; MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } @@ -211,7 +233,6 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) if(mPath.empty()) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - std::cout << "emptypath!"; return true; } nextPoint = *mPath.begin(); From e30af28860d82c5a85a7c1ef052fde6d01ab5ed9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 19:03:42 +0100 Subject: [PATCH 0051/1537] Markers should still have collision if they have a NiRootCollisionNode --- components/nifbullet/bulletnifloader.cpp | 19 +++++++++---------- components/nifbullet/bulletnifloader.hpp | 2 +- components/nifogre/ogrenifloader.cpp | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 04ac3d1410..08625ee9cb 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -112,7 +112,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) cShape->mHasCollisionNode = hasRootCollisionNode(node); //do a first pass - handleNode(mesh1, node,0,false,false); + handleNode(mesh1, node,0,false,false,false); if(mBoundingBox != NULL) { @@ -136,7 +136,7 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) btTriangleMesh* mesh2 = new btTriangleMesh(); - handleNode(mesh2, node,0,true,true); + handleNode(mesh2, node,0,true,true,false); if(mBoundingBox != NULL) { @@ -175,7 +175,7 @@ bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node const * node) void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node *node, int flags, bool isCollisionNode, - bool raycasting) + bool raycasting, bool isMarker) { // Accumulate the flags from all the child nodes. This works for all // the flags we currently use, at least. @@ -186,14 +186,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * else isCollisionNode = isCollisionNode && (node->recType != Nif::RC_RootCollisionNode); - // Marker objects: no collision + // Marker objects /// \todo don't do this in the editor std::string nodename = node->name; Misc::StringUtils::toLower(nodename); if (nodename.find("marker") != std::string::npos) - { - return; - } + isMarker = true; // Check for extra data Nif::Extra const *e = node; @@ -219,11 +217,12 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * // Marker objects. These are only visible in the // editor. Until and unless we add an editor component to // the engine, just skip this entire node. - return; + isMarker = true; } } - if (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) + if ( (isCollisionNode || (!cShape->mHasCollisionNode && !raycasting)) + && (!isMarker || (cShape->mHasCollisionNode && !raycasting))) { if(node->hasBounds) { @@ -246,7 +245,7 @@ void ManualBulletShapeLoader::handleNode(btTriangleMesh* mesh, const Nif::Node * for(size_t i = 0;i < list.length();i++) { if(!list[i].empty()) - handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting); + handleNode(mesh, list[i].getPtr(), flags, isCollisionNode, raycasting, isMarker); } } } diff --git a/components/nifbullet/bulletnifloader.hpp b/components/nifbullet/bulletnifloader.hpp index c231b75b68..7958f3b7cb 100644 --- a/components/nifbullet/bulletnifloader.hpp +++ b/components/nifbullet/bulletnifloader.hpp @@ -82,7 +82,7 @@ private: /** *Parse a node. */ - void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting); + void handleNode(btTriangleMesh* mesh, Nif::Node const *node, int flags, bool isCollisionNode, bool raycasting, bool isMarker); /** *Helper function diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 30c71023bc..3fc82f73ab 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1113,7 +1113,7 @@ public: { // Marker objects. These are only visible in the // editor. - flags |= 0x01; + return; } } e = e->extra; From 9efb073617cf41f66f774c9453574594fbcf2870 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 14 Mar 2013 18:05:00 +0000 Subject: [PATCH 0052/1537] clean up + correct a bug --- apps/openmw/mwmechanics/aitravel.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 57b9f66dde..94f6fd8928 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -40,8 +40,8 @@ float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) { - if(!grid) throw std::exception("NULL PathGrid!"); - if(grid->mPoints.empty()) throw std::exception("empty PathGrid!"); + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; @@ -54,7 +54,6 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) i0 = i; } } - std::cout << "distance:: " << m << "\n"; return i0; } @@ -175,7 +174,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) { - int sideX = sgn(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX); + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -185,7 +184,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) { - int sideY = sgn(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY); + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { @@ -193,10 +192,9 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) return true; } } - //std::cout << "npcpos" << pos.pos[0] << pos.pos[1] <mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; float xCell = 0; @@ -210,9 +208,11 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - - mPath = getPath(start,end,graph); + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); + mPath = getPath(start,end,graph); + } ESM::Pathgrid::Point dest; dest.mX = mX; From beab20cb42bea88073abff173b6e2410327f0796 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 19:53:57 +0100 Subject: [PATCH 0053/1537] Fix message boxes not opening if they opened as a result of object activation --- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f18c02a0e8..d9746fcfe4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -180,12 +180,12 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - activate(); if( MWBase::Environment::get().getWindowManager()->isGuiMode() && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); } + activate(); break; case A_Journal: toggleJournal (); From 2d8f0949a475d7dcf7b7854d9f4c601c46f8a954 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 20:27:16 +0100 Subject: [PATCH 0054/1537] Always run key (Y) --- apps/openmw/mwclass/npc.cpp | 18 ++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 5 ++++- apps/openmw/mwinput/inputmanagerimp.hpp | 2 +- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ apps/openmw/mwworld/player.cpp | 4 ++-- 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d4e5e5cd67..77b53ff1d9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,6 +322,24 @@ namespace MWClass return false; } + bool Npc::getForceStance(const MWWorld::Ptr& ptr, Stance stance) const + { + MWMechanics::NpcStats& stats = getNpcStats (ptr); + + switch (stance) + { + case Run: + return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun); + case Sneak: + return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak); + + case Combat: + return false; + } + + return false; + } + float Npc::getSpeed(const MWWorld::Ptr& ptr) const { const MWBase::World *world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index f41edb0df6..4698a1b9f3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -76,6 +76,9 @@ namespace MWClass virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. + virtual bool getForceStance (const MWWorld::Ptr& ptr, Stance stance) const; + ///< Check if a stance forced. + virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f18c02a0e8..72e9902837 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -193,7 +193,7 @@ namespace MWInput case A_AutoMove: toggleAutoMove (); break; - case A_ToggleWalk: + case A_AlwaysRun: toggleWalking (); break; case A_ToggleWeapon: @@ -768,6 +768,7 @@ namespace MWInput defaultKeyBindings[A_QuickKey10] = OIS::KC_0; defaultKeyBindings[A_Screenshot] = OIS::KC_SYSRQ; defaultKeyBindings[A_ToggleHUD] = OIS::KC_F12; + defaultKeyBindings[A_AlwaysRun] = OIS::KC_Y; std::map defaultMouseButtonBindings; defaultMouseButtonBindings[A_Inventory] = OIS::MB_Right; @@ -834,6 +835,7 @@ namespace MWInput descriptions[A_QuickKey8] = "sQuick8Cmd"; descriptions[A_QuickKey9] = "sQuick9Cmd"; descriptions[A_QuickKey10] = "sQuick10Cmd"; + descriptions[A_AlwaysRun] = "sAlways_Run"; if (descriptions[action] == "") return ""; // not configurable @@ -865,6 +867,7 @@ namespace MWInput ret.push_back(A_MoveRight); ret.push_back(A_TogglePOV); ret.push_back(A_Run); + ret.push_back(A_AlwaysRun); ret.push_back(A_Sneak); ret.push_back(A_Activate); ret.push_back(A_ToggleWeapon); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 8bb20b7bed..34c8327566 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -217,7 +217,7 @@ namespace MWInput A_CycleWeaponLeft,//Cycling through weapons A_CycleWeaponRight, A_ToggleSneak, //Toggles Sneak - A_ToggleWalk, //Toggle Walking/Running + A_AlwaysRun, //Toggle Walking/Running A_Sneak, A_QuickSave, diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..2bc4941a26 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -117,6 +117,11 @@ namespace MWWorld return false; } + bool Class::getForceStance (const Ptr& ptr, Stance stance) const + { + return false; + } + float Class::getSpeed (const Ptr& ptr) const { return 0; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1a6a16ca07..d36e3bc584 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -131,6 +131,9 @@ namespace MWWorld virtual void setForceStance (const Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. + virtual bool getForceStance (const Ptr& ptr, Stance stance) const; + ///< Check if a stance forced. + virtual void setStance (const Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 03dd1abc79..5407e3a684 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -81,9 +81,9 @@ namespace MWWorld { MWWorld::Ptr ptr = getPlayer(); - bool running = MWWorld::Class::get (ptr).getStance (ptr, MWWorld::Class::Run, true); + bool running = MWWorld::Class::get (ptr).getForceStance(ptr, MWWorld::Class::Run); - MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Run, !running); + MWWorld::Class::get (ptr).setForceStance(ptr, MWWorld::Class::Run, !running); } void Player::setSneak(bool sneak) From 5b943a965f5334356682511420715d35f522c847 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 21:08:19 +0100 Subject: [PATCH 0055/1537] Handle always run in the inputmanager, instead of using forced stance. --- apps/openmw/mwclass/npc.hpp | 2 +- apps/openmw/mwinput/inputmanagerimp.cpp | 9 +++++---- apps/openmw/mwinput/inputmanagerimp.hpp | 1 + apps/openmw/mwworld/class.cpp | 5 ----- apps/openmw/mwworld/class.hpp | 3 --- apps/openmw/mwworld/player.cpp | 9 --------- apps/openmw/mwworld/player.hpp | 1 - 7 files changed, 7 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 4698a1b9f3..bd624bd373 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -84,7 +84,7 @@ namespace MWClass virtual bool getStance (const MWWorld::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 MWWorld::Ptr& ptr) const; ///< Return movement speed. diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 72e9902837..006729b337 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -55,6 +55,7 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mOverencumberedMessageDelay(0.f) + , mAlwaysRunActive(false) { Ogre::RenderWindow* window = mOgre.getWindow (); size_t windowHnd; @@ -315,10 +316,10 @@ namespace MWInput else mPlayer.setUpDown (0); - if(actionIsActive(A_Run)) - mPlayer.setRunState(true); + if (mAlwaysRunActive) + mPlayer.setRunState(!actionIsActive(A_Run)); else - mPlayer.setRunState(false); + mPlayer.setRunState(actionIsActive(A_Run)); // if player tried to start moving, but can't (due to being overencumbered), display a notification. if (triedToMove) @@ -699,7 +700,7 @@ namespace MWInput void InputManager::toggleWalking() { if (mWindows.isGuiMode()) return; - mPlayer.toggleRunning(); + mAlwaysRunActive = !mAlwaysRunActive; } // Exit program now button (which is disabled in GUI mode) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 34c8327566..e181fb351d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -152,6 +152,7 @@ namespace MWInput int mMouseWheel; bool mDebug; bool mUserFileExists; + bool mAlwaysRunActive; std::map mControlSwitch; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2bc4941a26..71b24b65dc 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -117,11 +117,6 @@ namespace MWWorld return false; } - bool Class::getForceStance (const Ptr& ptr, Stance stance) const - { - return false; - } - float Class::getSpeed (const Ptr& ptr) const { return 0; diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index d36e3bc584..1a6a16ca07 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -131,9 +131,6 @@ namespace MWWorld virtual void setForceStance (const Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. - virtual bool getForceStance (const Ptr& ptr, Stance stance) const; - ///< Check if a stance forced. - virtual void setStance (const Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 5407e3a684..0dc8b37eff 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -77,15 +77,6 @@ namespace MWWorld MWWorld::Class::get(ptr).setStance(ptr, MWWorld::Class::Run, run); } - void Player::toggleRunning() - { - MWWorld::Ptr ptr = getPlayer(); - - bool running = MWWorld::Class::get (ptr).getForceStance(ptr, MWWorld::Class::Run); - - MWWorld::Class::get (ptr).setForceStance(ptr, MWWorld::Class::Run, !running); - } - void Player::setSneak(bool sneak) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 5f2fc3a08b..d82d3fc329 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -66,7 +66,6 @@ namespace MWWorld void setUpDown(int value); void setRunState(bool run); - void toggleRunning(); void setSneak(bool sneak); }; } From b36295cbb3b87d45c78bcc8893da4eef25525d44 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 14 Mar 2013 21:10:22 +0100 Subject: [PATCH 0056/1537] Removed a leftover --- apps/openmw/mwclass/npc.cpp | 18 ------------------ apps/openmw/mwclass/npc.hpp | 3 --- 2 files changed, 21 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 77b53ff1d9..d4e5e5cd67 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -322,24 +322,6 @@ namespace MWClass return false; } - bool Npc::getForceStance(const MWWorld::Ptr& ptr, Stance stance) const - { - MWMechanics::NpcStats& stats = getNpcStats (ptr); - - switch (stance) - { - case Run: - return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun); - case Sneak: - return stats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak); - - case Combat: - return false; - } - - return false; - } - float Npc::getSpeed(const MWWorld::Ptr& ptr) const { const MWBase::World *world = MWBase::Environment::get().getWorld(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index bd624bd373..51e93636d3 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -76,9 +76,6 @@ namespace MWClass virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; ///< Force or unforce a stance. - virtual bool getForceStance (const MWWorld::Ptr& ptr, Stance stance) const; - ///< Check if a stance forced. - virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const; ///< Set or unset a stance. From 521bebd2f403b3aaae6a10b50f563abc8f00df29 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:17:30 +0100 Subject: [PATCH 0057/1537] Fallback system rewritten, added light fallbacks --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 4 - apps/openmw/mwrender/objects.cpp | 41 ++++--- apps/openmw/mwrender/objects.hpp | 17 +-- apps/openmw/mwrender/renderingmanager.cpp | 5 +- apps/openmw/mwrender/renderingmanager.hpp | 4 +- apps/openmw/mwworld/fallback.cpp | 46 ++++++++ apps/openmw/mwworld/fallback.hpp | 17 +++ apps/openmw/mwworld/weather.cpp | 127 ++++++++-------------- apps/openmw/mwworld/weather.hpp | 10 +- apps/openmw/mwworld/worldimp.cpp | 24 +--- apps/openmw/mwworld/worldimp.hpp | 7 +- 12 files changed, 163 insertions(+), 141 deletions(-) create mode 100644 apps/openmw/mwworld/fallback.cpp create mode 100644 apps/openmw/mwworld/fallback.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8df2136e5e..0edc18afba 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -53,7 +53,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp + esmstore store recordcmp fallback ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 6cd5b90b40..642291eefb 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -103,12 +103,8 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual void setFallbackValues (const std::map& fallbackMap) = 0; - virtual std::string getFallback (const std::string& key) const = 0; - virtual std::string getFallback (const std::string& key, const std::string& def) const = 0; - virtual MWWorld::Player& getPlayer() = 0; virtual const MWWorld::ESMStore& getStore() const = 0; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index cb1dfa75be..23d35c65f0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -16,16 +16,31 @@ #include "renderconst.hpp" using namespace MWRender; +float Objects::lightLinearValue() +{ + return mFallback->getFallbackFloat("LightAttenuation_LinearValue"); +} +float Objects::lightLinearRadiusMult() +{ + return mFallback->getFallbackFloat("LightAttenuation_LinearRadiusMult"); +} +float Objects::lightQuadraticValue() +{ + return mFallback->getFallbackFloat("LightAttenuation_QuadraticValue"); +} +float Objects::lightQuadraticRadiusMult() +{ + return mFallback->getFallbackFloat("LightAttenuation_QuadraticRadiusMult"); +} -/// \todo Replace these, once fallback values from the ini file are available. -float Objects::lightLinearValue = 3; -float Objects::lightLinearRadiusMult = 1; - -float Objects::lightQuadraticValue = 16; -float Objects::lightQuadraticRadiusMult = 1; - -bool Objects::lightOutQuadInLin = true; -bool Objects::lightQuadratic = false; +bool Objects::lightOutQuadInLin() +{ + return mFallback->getFallbackBool("LightAttenuation_OutQuadInLin"); +} +bool Objects::lightQuadratic() +{ + return mFallback->getFallbackBool("LightAttenuation_UseQuadratic"); +} int Objects::uniqueID = 0; @@ -269,14 +284,14 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre if (!quadratic) { - float r = radius * lightLinearRadiusMult; - float attenuation = lightLinearValue / r; + float r = radius * lightLinearRadiusMult(); + float attenuation = lightLinearValue() / r; light->setAttenuation(r*10, 0, attenuation, 0); } else { - float r = radius * lightQuadraticRadiusMult; - float attenuation = lightQuadraticValue / pow(r, 2); + float r = radius * lightQuadraticRadiusMult(); + float attenuation = lightQuadraticValue() / pow(r, 2); light->setAttenuation(r*10, 0, 0, attenuation); } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 73e95a3c53..cfe5243061 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -5,6 +5,7 @@ #include #include +#include "../mwworld/fallback.hpp" namespace MWWorld { @@ -56,21 +57,21 @@ class Objects{ Ogre::SceneNode* mRootNode; bool mIsStatic; static int uniqueID; + MWWorld::Fallback* mFallback; + float lightLinearValue(); + float lightLinearRadiusMult(); - static float lightLinearValue; - static float lightLinearRadiusMult; + bool lightQuadratic(); + float lightQuadraticValue(); + float lightQuadraticRadiusMult(); - static bool lightQuadratic; - static float lightQuadraticValue; - static float lightQuadraticRadiusMult; - - static bool lightOutQuadInLin; + bool lightOutQuadInLin(); void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mIsStatic(false) {} + Objects(OEngine::Render::OgreRenderer& renderer, MWWorld::Fallback* fallback): mRenderer (renderer), mIsStatic(false), mFallback(fallback) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light=false); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e6216b5372..3a15582ba0 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -48,9 +48,10 @@ using namespace Ogre; namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback) : mRendering(_rend) - , mObjects(mRendering) + , mFallback(fallback) + , mObjects(mRendering,mFallback) , mActors(mRendering, this) , mAmbientMode(0) , mSunEnabled(0) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1777a72c33..fd43438ca5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -60,7 +60,7 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList public: RenderingManager(OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, - const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine); + const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine,MWWorld::Fallback* fallback); virtual ~RenderingManager(); void togglePOV() { @@ -220,6 +220,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList bool mSunEnabled; + MWWorld::Fallback* mFallback; + SkyManager* mSkyManager; OcclusionQuery* mOcclusionQuery; diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp new file mode 100644 index 0000000000..24ddc3db7b --- /dev/null +++ b/apps/openmw/mwworld/fallback.cpp @@ -0,0 +1,46 @@ +#include "fallback.hpp" +#include "boost/lexical_cast.hpp" +namespace MWWorld +{ + std::string Fallback::getFallbackString(const std::string& fall) const + { + std::map::const_iterator it; + if((it = mFallbackMap.find(fall)) == mFallbackMap.end()) + { + return ""; + } + return it->second; + } + float Fallback::getFallbackFloat(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback=="") + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback=="") + return false; + else + return boost::lexical_cast(fallback); + } + Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const + { + std::string sum=getFallbackString(fall); + if(sum=="") + return Ogre::ColourValue(0,0,0); + else + { + std::string ret[3]; + unsigned int j=0; + for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); + } + } +} diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp new file mode 100644 index 0000000000..f2602c9776 --- /dev/null +++ b/apps/openmw/mwworld/fallback.hpp @@ -0,0 +1,17 @@ +#ifndef GAME_MWWORLD_FALLBACK_H +#define GAME_MWWORLD_FALLBACK_H +#include +namespace MWWorld +{ + class Fallback + { + const std::map mFallbackMap; + public: + Fallback(const std::map fallback):mFallbackMap(fallback){}; + std::string getFallbackString(const std::string& fall) const; + float getFallbackFloat(const std::string& fall) const; + bool getFallbackBool(const std::string& fall) const; + Ogre::ColourValue getFallbackColour(const std::string& fall) const; + }; +} +#endif diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 052ae4e028..2722bf80ea 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -4,7 +4,6 @@ #include #include -#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" @@ -19,100 +18,68 @@ using namespace MWWorld; using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) -std::string WeatherManager::getFallback (const std::string& key) const -{ - std::map::const_iterator it; - if((it = mFallback.find(key)) == mFallback.end()) - { - return ""; - } - return it->second; -} -std::string WeatherManager::getFallbackString(const std::string& fall) const -{ - return getFallback(fall); -} - -float WeatherManager::getFallbackFloat(const std::string& fall) const -{ - std::string fallback=getFallbackString(fall); - return boost::lexical_cast(fallback); -} - -ColourValue WeatherManager::getFallbackColour(const std::string& fall) const -{ - std::string sum; - std::string ret[3]; - sum=getFallback(fall); - unsigned int j=0; - for(unsigned int i=0;i(ret[0])/255.f,boost::lexical_cast(ret[1])/255.f,boost::lexical_cast(ret[2])/255.f); -} void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); - weather.mTransitionDelta = getFallbackFloat("Weather_"+upper+"_Transition_Delta"); - weather.mSkySunriseColor=getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); - weather.mSkyDayColor = getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); - weather.mSkySunsetColor = getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); - weather.mSkyNightColor = getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); - weather.mFogSunriseColor = getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); - weather.mFogDayColor = getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); - weather.mFogSunsetColor = getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); - weather.mFogNightColor = getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); - weather.mAmbientSunriseColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); - weather.mAmbientDayColor = getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); - weather.mAmbientSunsetColor = getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); - weather.mAmbientNightColor = getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); - weather.mSunSunriseColor = getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); - weather.mSunDayColor = getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); - weather.mSunSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); - weather.mSunNightColor = getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); - weather.mSunDiscSunsetColor = getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); - weather.mLandFogDayDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); - weather.mLandFogNightDepth = getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); - weather.mWindSpeed = getFallbackFloat("Weather_"+upper+"_Wind_Speed"); - weather.mCloudSpeed = getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); - weather.mGlareView = getFallbackFloat("Weather_"+upper+"_Glare_View"); + std::string upper=name; + upper[0]=toupper(name[0]); + weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); + weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); + weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); + weather.mSkySunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunset_Color"); + weather.mSkyNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Night_Color"); + weather.mFogSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunrise_Color"); + weather.mFogDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Day_Color"); + weather.mFogSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Sunset_Color"); + weather.mFogNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Fog_Night_Color"); + weather.mAmbientSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunrise_Color"); + weather.mAmbientDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Day_Color"); + weather.mAmbientSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Sunset_Color"); + weather.mAmbientNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Ambient_Night_Color"); + weather.mSunSunriseColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunrise_Color"); + weather.mSunDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Day_Color"); + weather.mSunSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Sunset_Color"); + weather.mSunNightColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Night_Color"); + weather.mSunDiscSunsetColor = mFallback->getFallbackColour("Weather_"+upper+"_Sun_Disc_Sunset_Color"); + weather.mLandFogDayDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Day_Depth"); + weather.mLandFogNightDepth = mFallback->getFallbackFloat("Weather_"+upper+"_Land_Fog_Night_Depth"); + weather.mWindSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Wind_Speed"); + weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed"); + weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View"); mWeatherSettings[name] = weather; } -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,const std::map& fallbackMap) : +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fallback* fallback) : mHour(14), mCurrentWeather("clear"), mFirstUpdate(true), mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0), mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0), mMonth(0), mDay(0), - mTimePassed(0), mFallback(fallbackMap) + mTimePassed(0), mFallback(fallback) { mRendering = rendering; - //Globals - mThunderSoundID0 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; - //Weather - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - setFallbackWeather(clear,"clear"); + //Globals + mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); + mWeatherUpdateTime = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundDelay = 0.25; + //Weather + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; + foggy.mCloudTexture = "tx_sky_foggy.dds"; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index b5bd0e10a0..ae0c2ca93b 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -3,7 +3,7 @@ #include #include - +#include "fallback.hpp" namespace MWRender { class RenderingManager; @@ -112,7 +112,7 @@ namespace MWWorld class WeatherManager { public: - WeatherManager(MWRender::RenderingManager*,const std::map& fallbackMap); + WeatherManager(MWRender::RenderingManager*,MWWorld::Fallback* fallback); /** * Change the weather in the specified region @@ -141,11 +141,7 @@ namespace MWWorld private: float mHour; int mDay, mMonth; - std::map mFallback; - std::string getFallback (const std::string& key) const; - std::string getFallbackString(const std::string& fall) const; - float getFallbackFloat(const std::string& fall) const; - Ogre::ColourValue getFallbackColour(const std::string& fall) const; + MWWorld::Fallback* mFallback; void setFallbackWeather(Weather& weather,const std::string& name); MWRender::RenderingManager* mRendering; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a933713dd7..5a23aae972 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -154,24 +154,9 @@ namespace MWWorld mRendering->skyDisable(); } - void World::setFallbackValues (const std::map& fallbackMap) - { - mFallback = fallbackMap; - } - std::string World::getFallback (const std::string& key) const { - return getFallback(key, ""); - } - - std::string World::getFallback (const std::string& key, const std::string& def) const - { - std::map::const_iterator it; - if((it = mFallback.find(key)) == mFallback.end()) - { - return def; - } - return it->second; + return mFallback.getFallbackString(key); } World::World (OEngine::Render::OgreRenderer& renderer, @@ -181,17 +166,16 @@ namespace MWWorld ToUTF8::Utf8Encoder* encoder, const std::map& fallbackMap, int mActivationDistanceOverride) : mPlayer (0), mLocalScripts (mStore), mGlobalVariables (0), mSky (true), mCells (mStore, mEsm), - mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride), - mFallback (fallbackMap) + mNumFacing(0), mActivationDistanceOverride (mActivationDistanceOverride),mFallback(fallbackMap) { mPhysics = new PhysicsSystem(renderer); mPhysEngine = mPhysics->getEngine(); - mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine); + mRendering = new MWRender::RenderingManager(renderer, resDir, cacheDir, mPhysEngine,&mFallback); mPhysEngine->setSceneManager(renderer.getScene()); - mWeatherManager = new MWWorld::WeatherManager(mRendering,fallbackMap); + mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); int idx = 0; // NOTE: We might need to reserve one more for the running game / save. diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index e06b89f600..526e68a77a 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -10,6 +10,7 @@ #include "cells.hpp" #include "localscripts.hpp" #include "timestamp.hpp" +#include "fallback.hpp" #include "../mwbase/world.hpp" @@ -49,6 +50,7 @@ namespace MWWorld class World : public MWBase::World { + MWWorld::Fallback mFallback; MWRender::RenderingManager* mRendering; MWWorld::WeatherManager* mWeatherManager; @@ -82,7 +84,6 @@ namespace MWWorld float mFaced1Distance; float mFaced2Distance; int mNumFacing; - std::map mFallback; unsigned long lastTick; Ogre::Timer mTimer; @@ -132,12 +133,8 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual void setFallbackValues (const std::map& fallbackMap); - virtual std::string getFallback (const std::string& key) const; - virtual std::string getFallback (const std::string& key, const std::string& def) const; - virtual Player& getPlayer(); virtual const MWWorld::ESMStore& getStore() const; From e1c6c3fe0259313e158dcc8333b960b00cd53687 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:22:02 +0100 Subject: [PATCH 0058/1537] Tabulators deleted --- apps/openmw/mwworld/weather.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 2722bf80ea..db8787af7e 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -70,16 +70,16 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); mThunderSoundDelay = 0.25; //Weather - Weather clear; - clear.mCloudTexture = "tx_sky_clear.dds"; - setFallbackWeather(clear,"clear"); + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + setFallbackWeather(clear,"clear"); Weather cloudy; - cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; setFallbackWeather(cloudy,"cloudy"); Weather foggy; - foggy.mCloudTexture = "tx_sky_foggy.dds"; + foggy.mCloudTexture = "tx_sky_foggy.dds"; setFallbackWeather(foggy,"foggy"); Weather thunderstorm; From 542c1bcc531307fa02171f9f6dd2574bd26bf691 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:28:39 +0100 Subject: [PATCH 0059/1537] Some other tabulators deleted --- apps/openmw/mwworld/weather.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index db8787af7e..d98815de7b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -20,9 +20,9 @@ using namespace MWSound; #define lerp(x, y) (x * (1-factor) + y * factor) void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name) { - std::string upper=name; - upper[0]=toupper(name[0]); - weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); + std::string upper=name; + upper[0]=toupper(name[0]); + weather.mCloudsMaximumPercent = mFallback->getFallbackFloat("Weather_"+upper+"_Clouds_Maximum_Percent"); weather.mTransitionDelta = mFallback->getFallbackFloat("Weather_"+upper+"_Transition_Delta"); weather.mSkySunriseColor=mFallback->getFallbackColour("Weather_"+upper+"_Sky_Sunrise_Color"); weather.mSkyDayColor = mFallback->getFallbackColour("Weather_"+upper+"_Sky_Day_Color"); @@ -57,19 +57,19 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa { mRendering = rendering; //Globals - mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); - mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); - mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); - mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); - mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); - mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); - mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); - mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); - mWeatherUpdateTime = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); - mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); - mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); - mThunderSoundDelay = 0.25; - //Weather + mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); + mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); + mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); + mThunderSoundID3 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_3"); + mSunriseTime = mFallback->getFallbackFloat("Weather_Sunrise_Time"); + mSunsetTime = mFallback->getFallbackFloat("Weather_Sunset_Time"); + mSunriseDuration = mFallback->getFallbackFloat("Weather_Sunrise_Duration"); + mSunsetDuration = mFallback->getFallbackFloat("Weather_Sunset_Duration"); + mWeatherUpdateTime = mFallback->getFallbackFloat("Weather_Hours_Between_Weather_Changes"); + mThunderFrequency = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Frequency"); + mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold"); + mThunderSoundDelay = 0.25; + //Weather Weather clear; clear.mCloudTexture = "tx_sky_clear.dds"; setFallbackWeather(clear,"clear"); From 727a598cbe693388e5f32262aff578d3ce8992d5 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 15 Mar 2013 10:32:03 +0100 Subject: [PATCH 0060/1537] Last tabulator died --- apps/openmw/mwworld/weather.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d98815de7b..3462cfca1c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -56,7 +56,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa mTimePassed(0), mFallback(fallback) { mRendering = rendering; - //Globals + //Globals mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0"); mThunderSoundID1 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_1"); mThunderSoundID2 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_2"); From 66a2df68db176a1a40fa284318ee52ca9d32c270 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 15 Mar 2013 10:26:04 +0100 Subject: [PATCH 0061/1537] some cleanup --- apps/openmw/mwworld/fallback.cpp | 11 +++++++---- apps/openmw/mwworld/fallback.hpp | 7 ++++++- apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/weather.hpp | 4 +++- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index 24ddc3db7b..569a6b50c2 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -2,6 +2,9 @@ #include "boost/lexical_cast.hpp" namespace MWWorld { + Fallback::Fallback(const std::map& fallback):mFallbackMap(fallback) + {} + std::string Fallback::getFallbackString(const std::string& fall) const { std::map::const_iterator it; @@ -14,7 +17,7 @@ namespace MWWorld float Fallback::getFallbackFloat(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback=="") + if(fallback.empty()) return 0; else return boost::lexical_cast(fallback); @@ -22,7 +25,7 @@ namespace MWWorld bool Fallback::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); - if(fallback=="") + if(fallback.empty()) return false; else return boost::lexical_cast(fallback); @@ -30,13 +33,13 @@ namespace MWWorld Ogre::ColourValue Fallback::getFallbackColour(const std::string& fall) const { std::string sum=getFallbackString(fall); - if(sum=="") + if(sum.empty()) return Ogre::ColourValue(0,0,0); else { std::string ret[3]; unsigned int j=0; - for(unsigned int i=0;i +#include + #include + namespace MWWorld { class Fallback { const std::map mFallbackMap; public: - Fallback(const std::map fallback):mFallbackMap(fallback){}; + Fallback(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3462cfca1c..867e910fe3 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -12,6 +12,7 @@ #include "player.hpp" #include "esmstore.hpp" +#include "fallback.hpp" using namespace Ogre; using namespace MWWorld; diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index ae0c2ca93b..93d908ebe5 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -3,7 +3,7 @@ #include #include -#include "fallback.hpp" + namespace MWRender { class RenderingManager; @@ -11,6 +11,8 @@ namespace MWRender namespace MWWorld { + class Fallback; + /// Defines the actual weather that results from weather setting (see below), time of day and weather transition struct WeatherResult { From 485b6c855a1ce395eda8127914588ff516f10b9f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 15 Mar 2013 16:44:35 +0100 Subject: [PATCH 0062/1537] Fix NPC race height not being applied --- apps/openmw/mwclass/npc.cpp | 14 ++++++++++++++ apps/openmw/mwclass/npc.hpp | 2 ++ apps/openmw/mwrender/characterpreview.cpp | 9 ++++++--- apps/openmw/mwrender/npcanimation.cpp | 5 ----- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ 5 files changed, 24 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d4e5e5cd67..2ed285a813 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -511,6 +511,20 @@ namespace MWClass x = 0; } + void Npc::adjustScale(const MWWorld::Ptr &ptr, float &scale) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + const ESM::Race* race = + MWBase::Environment::get().getWorld()->getStore().get().find(ref->mBase->mRace); + + if (ref->mBase->isMale()) + scale *= race->mData.mHeight.mMale; + else + scale *= race->mData.mHeight.mFemale; + } + MWWorld::Ptr Npc::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 51e93636d3..0ca6a8d69e 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -110,6 +110,8 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? + virtual void adjustScale (const MWWorld::Ptr &ptr, float &scale) const; + virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c99e426624..843bcf007b 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -104,11 +104,14 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + float scale=1.f; + MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); + mNode->setScale(Ogre::Vector3(scale)); + mNode->setVisible (false); - Ogre::Vector3 scale = mNode->getScale(); - mCamera->setPosition(mPosition * scale); - mCamera->lookAt(mLookAt * scale); + mCamera->setPosition(mPosition * mNode->getScale()); + mCamera->lookAt(mLookAt * mNode->getScale()); onSetup(); } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 9da70beb45..b76a38c469 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -85,11 +85,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor MWBase::Environment::get().getWorld()->getStore(); const ESM::Race *race = store.get().find(mNpc->mRace); - float scale = race->mData.mHeight.mMale; - if(!mNpc->isMale()) - scale = race->mData.mHeight.mFemale; - node->scale(Ogre::Vector3(scale)); - mHeadModel = "meshes\\" + store.get().find(mNpc->mHead)->mModel; mHairModel = "meshes\\" + store.get().find(mNpc->mHair)->mModel; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3a15582ba0..1bab676c3c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -885,6 +885,8 @@ void RenderingManager::renderPlayer(const MWWorld::Ptr &ptr) mPlayer->setAnimation(anim); mWater->removeEmitter (ptr); mWater->addEmitter (ptr); + // apply race height + MWBase::Environment::get().getWorld()->scaleObject(ptr, 1.f); } void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw) From c0b0227e8a494ea27cdc0c82df20ff4929e015d6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 19:00:14 +0100 Subject: [PATCH 0063/1537] enchanting --- apps/openmw/mwclass/armor.cpp | 8 ++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/clothing.cpp | 8 ++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 8 ++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwgui/container.cpp | 70 ++++++++--- apps/openmw/mwgui/container.hpp | 23 ++-- apps/openmw/mwgui/dialogue.cpp | 4 +- apps/openmw/mwgui/enchantingdialog.cpp | 130 ++++++++++++++++++++ apps/openmw/mwgui/enchantingdialog.hpp | 31 +++++ apps/openmw/mwgui/itemselection.cpp | 2 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwworld/class.cpp | 5 + apps/openmw/mwworld/class.hpp | 3 + files/mygui/openmw_chargen_race.layout | 6 +- files/mygui/openmw_enchanting_dialog.layout | 15 ++- 17 files changed, 281 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fdf211c28a..130c0515d0 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -290,4 +290,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mArmors.insert(*ref), &cell); } + + short Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 51c0ea21c9..ff45411ed2 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -70,6 +70,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index dfced6daa8..f5f71a7767 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,4 +238,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mClothes.insert(*ref), &cell); } + + short Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index f7801848f6..f01c78afce 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -64,6 +64,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 475c08ccbf..0f6e86811e 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -378,4 +378,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mWeapons.insert(*ref), &cell); } + + short Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 06cf88c5f2..bf34172516 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -70,6 +70,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2b80003127..1b4a982765 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -68,6 +68,16 @@ namespace return compareType(left.getTypeName(), right.getTypeName()); } } + + bool isChargedSoulstone (MWWorld::Ptr ptr) + { + if (ptr.getTypeName() != typeid(ESM::Miscellaneous).name()) + return false; + MWWorld::LiveCellRef *ref = + ptr.get(); + + return (ref->mRef.mSoul != ""); + } } @@ -345,7 +355,7 @@ void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); } -void ContainerBase::setFilter(ContainerBase::Filter filter) +void ContainerBase::setFilter(int filter) { mFilter = filter; drawItems(); @@ -369,29 +379,34 @@ void ContainerBase::drawItems() int maxHeight = mItemView->getSize().height - 58; bool onlyMagic = false; + bool noMagic = false; int categories = 0; - 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) + if (mFilter & Filter_All) + categories |= MWWorld::ContainerStore::Type_All; + if (mFilter & Filter_Weapon) + categories |= MWWorld::ContainerStore::Type_Weapon; + if (mFilter & Filter_Apparel) + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; + 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; + 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) + if (mFilter & Filter_Misc) { - 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_Probe; + 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_Probe; } - else if (mFilter == Filter_Ingredients) - categories = MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_Ingredients) + categories |= MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_ChargedSoulstones) + categories |= MWWorld::ContainerStore::Type_Miscellaneous; + if (mFilter & Filter_NoMagic) + noMagic = true; /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them @@ -466,12 +481,29 @@ void ContainerBase::drawItems() { const MWWorld::Ptr* iter = &((*it).first); + + if (onlyMagic + && it->second != ItemState_Barter + && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" + && iter->getTypeName() != typeid(ESM::Potion).name()) + continue; + + if (noMagic + && it->second != ItemState_Barter + && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" + || iter->getTypeName() == typeid(ESM::Potion).name())) + continue; + + if ( (mFilter & Filter_ChargedSoulstones) + && !isChargedSoulstone(*iter)) + continue; + int displayCount = iter->getRefData().getCount(); if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) { displayCount -= mDragAndDrop->mDraggedCount; } - if(displayCount > 0 && !(onlyMagic && it->second != ItemState_Barter && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) + if(displayCount > 0) { 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 3c8127b26c..49e60aa251 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -48,16 +48,17 @@ namespace MWGui ContainerBase(DragAndDrop* dragAndDrop); virtual ~ContainerBase(); - enum Filter - { - Filter_All = 0x01, - Filter_Weapon = 0x02, - Filter_Apparel = 0x03, - Filter_Magic = 0x04, - Filter_Misc = 0x05, + // basic types (inclusive) + static const int Filter_All = (1<<0); + static const int Filter_Weapon = (1<<1); + static const int Filter_Apparel = (1<<2); + static const int Filter_Ingredients = (1<<3); + static const int Filter_Misc = (1<<4); - Filter_Ingredients = 0x06 - }; + // special filtering (exclusive) + static const int Filter_Magic = (1<<5); + static const int Filter_NoMagic = (1<<6); + static const int Filter_ChargedSoulstones = (1<<7); enum ItemState { @@ -78,7 +79,7 @@ namespace MWGui MWWorld::ContainerStore& getBoughtItems() { return mBoughtItems; } void openContainer(MWWorld::Ptr container); - void setFilter(Filter filter); ///< set category filter + void setFilter(int filter); ///< set category filter void drawItems(); protected: @@ -92,7 +93,7 @@ namespace MWGui DragAndDrop* mDragAndDrop; - Filter mFilter; + int mFilter; // bought items are put in a separate ContainerStore so that they don't stack with other (not bought) items. MWWorld::ContainerStore mBoughtItems; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index cdcbfc4d18..d4125a05f0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -316,8 +316,8 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_CreateSpells) mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); -// if (mServices & Service_Enchant) -// mTopicsList->addItem(gmst.find("sEnchanting")->getString()); + if (mServices & Service_Enchant) + mTopicsList->addItem(gmst.find("sEnchanting")->getString()); if (mServices & Service_Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 3bd67ade63..673739cbf3 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -1,5 +1,13 @@ #include "enchantingdialog.hpp" +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwworld/player.hpp" + +#include "itemselection.hpp" +#include "container.hpp" namespace MWGui { @@ -8,19 +16,45 @@ namespace MWGui EnchantingDialog::EnchantingDialog(MWBase::WindowManager &parWindowManager) : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) + , mItemSelectionDialog(NULL) + , mCurrentEnchantmentPoints(0) { getWidget(mCancelButton, "CancelButton"); getWidget(mAvailableEffectsList, "AvailableEffects"); getWidget(mUsedEffectsView, "UsedEffects"); + getWidget(mItemBox, "ItemBox"); + getWidget(mSoulBox, "SoulBox"); + getWidget(mEnchantmentPoints, "Enchantment"); + getWidget(mCastCost, "CastCost"); + getWidget(mCharge, "Charge"); + getWidget(mTypeButton, "TypeButton"); + getWidget(mBuyButton, "BuyButton"); + getWidget(mPrice, "PriceLabel"); setWidgets(mAvailableEffectsList, mUsedEffectsView); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onCancelButtonClicked); + mItemBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectItem); + mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); + } + + EnchantingDialog::~EnchantingDialog() + { + delete mItemSelectionDialog; } void EnchantingDialog::open() { center(); + onRemoveItem(NULL); + onRemoveSoul(NULL); + } + + void EnchantingDialog::updateLabels() + { + mEnchantmentPoints->setCaption(boost::lexical_cast(mCurrentEnchantmentPoints) + + " / " + (mItem.isEmpty() ? "0" : boost::lexical_cast( + MWWorld::Class::get(mItem).getEnchantmentPoints(mItem)))); } void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) @@ -40,4 +74,100 @@ namespace MWGui { mWindowManager.removeGuiMode (GM_Enchanting); } + + void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) + { + delete mItemSelectionDialog; + mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, mWindowManager); + mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); + mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); + mItemSelectionDialog->setVisible(true); + mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + mItemSelectionDialog->drawItems (); + } + + void EnchantingDialog::onItemSelected(MWWorld::Ptr item) + { + mItemSelectionDialog->setVisible(false); + + while (mItemBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); + + MyGUI::ImageBox* image = mItemBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(item); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); + + mItem = item; + updateLabels(); + } + + void EnchantingDialog::onRemoveItem(MyGUI::Widget *sender) + { + while (mItemBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); + mItem = MWWorld::Ptr(); + updateLabels(); + } + + void EnchantingDialog::onItemCancel() + { + mItemSelectionDialog->setVisible(false); + } + + void EnchantingDialog::onSoulSelected(MWWorld::Ptr item) + { + mItemSelectionDialog->setVisible(false); + + while (mSoulBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); + + MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(item); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); + + mSoul = item; + updateLabels(); + } + + void EnchantingDialog::onRemoveSoul(MyGUI::Widget *sender) + { + while (mSoulBox->getChildCount ()) + MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); + mSoul = MWWorld::Ptr(); + updateLabels(); + } + + void EnchantingDialog::onSoulCancel() + { + mItemSelectionDialog->setVisible(false); + } + + void EnchantingDialog::onSelectSoul(MyGUI::Widget *sender) + { + delete mItemSelectionDialog; + mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, mWindowManager); + mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); + mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); + mItemSelectionDialog->setVisible(true); + mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + mItemSelectionDialog->drawItems (); + + //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); + } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 0415c9d8df..bcebb799df 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -10,10 +10,13 @@ namespace MWGui { + class ItemSelectionDialog; + class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: EnchantingDialog(MWBase::WindowManager& parWindowManager); + virtual ~EnchantingDialog(); virtual void open(); void startEnchanting(MWWorld::Ptr actor); @@ -22,8 +25,36 @@ namespace MWGui virtual void onReferenceUnavailable(); void onCancelButtonClicked(MyGUI::Widget* sender); + void onSelectItem (MyGUI::Widget* sender); + void onSelectSoul (MyGUI::Widget* sender); + void onRemoveItem (MyGUI::Widget* sender); + void onRemoveSoul (MyGUI::Widget* sender); + + void onItemSelected(MWWorld::Ptr item); + void onItemCancel(); + void onSoulSelected(MWWorld::Ptr item); + void onSoulCancel(); + + void updateLabels(); + + ItemSelectionDialog* mItemSelectionDialog; MyGUI::Button* mCancelButton; + MyGUI::ImageBox* mItemBox; + MyGUI::ImageBox* mSoulBox; + + MyGUI::Button* mTypeButton; + MyGUI::Button* mBuyButton; + + MyGUI::TextBox* mEnchantmentPoints; + MyGUI::TextBox* mCastCost; + MyGUI::TextBox* mCharge; + MyGUI::TextBox* mPrice; + + MWWorld::Ptr mItem; + MWWorld::Ptr mSoul; + + float mCurrentEnchantmentPoints; }; } diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 14b1cf8ee5..4b8adcef4f 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,7 +3,7 @@ namespace MWGui { - ItemSelectionDialog::ItemSelectionDialog(const std::string &label, ContainerBase::Filter filter, MWBase::WindowManager& parWindowManager) + ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter, MWBase::WindowManager& parWindowManager) : ContainerBase(NULL) , WindowModal("openmw_itemselection_dialog.layout", parWindowManager) { diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index cab125f1f8..733daa91ae 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -8,7 +8,7 @@ namespace MWGui class ItemSelectionDialog : public ContainerBase, public WindowModal { public: - ItemSelectionDialog(const std::string& label, ContainerBase::Filter filter, MWBase::WindowManager& parWindowManager); + ItemSelectionDialog(const std::string& label, int filter, MWBase::WindowManager& parWindowManager); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..cc20aeda75 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -127,6 +127,11 @@ namespace MWWorld return 0; } + short Class::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error ("class does not support enchanting"); + } + MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const { throw std::runtime_error ("movement settings not supported by class"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1a6a16ca07..77c29fe489 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -222,6 +222,9 @@ namespace MWWorld ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + ///< @return the number of enchantment points available for possible enchanting + virtual void adjustScale(const MWWorld::Ptr& ptr,float& scale) const; virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index 4ef8da0f3f..c0b04618ed 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index a19c569256..2549fd26f9 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -26,14 +26,18 @@ - + + + - + + + @@ -85,7 +89,11 @@ - + + + + + @@ -97,6 +105,7 @@ + From cebcbe11f8f8fca480b6271b568761c7f03e8036 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 20:32:21 +0100 Subject: [PATCH 0064/1537] Implemented service refusal --- apps/openmw/mwbase/dialoguemanager.hpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 31 ++++++++++ apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 + apps/openmw/mwdialogue/filter.cpp | 13 ++-- apps/openmw/mwdialogue/filter.hpp | 6 +- apps/openmw/mwgui/dialogue.cpp | 60 ++++++++++--------- 6 files changed, 76 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index a205e78db7..db86385d4e 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -41,6 +41,8 @@ namespace MWBase virtual void goodbyeSelected() = 0; virtual void questionAnswered (const std::string& answer) = 0; + virtual bool checkServiceRefused () = 0; + virtual void persuade (int type) = 0; virtual int getTemporaryDispositionChange () const = 0; virtual void applyTemporaryDispositionChange (int delta) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 35f0c94937..62ee09bdba 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -518,6 +518,37 @@ namespace MWDialogue mTemporaryDispositionChange += delta; } + bool DialogueManager::checkServiceRefused() + { + Filter filter (mActor, mChoice, mTalkedTo); + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& dialogue = *dialogues.find ("Service Refusal"); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + + std::vector infos = filter.list (dialogue, false, false, true); + if (!infos.empty()) + { + const ESM::DialInfo* info = infos[0]; + + parseText (info->mResponse); + + const MWWorld::Store& gmsts = + MWBase::Environment::get().getWorld()->getStore().get(); + + win->addTitle (gmsts.find ("sServiceRefusal")->getString()); + + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); + win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); + + executeScript (info->mResultScript); + return true; + } + return false; + } + std::vector ParseHyperText(const std::string& text) { std::vector result; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 1ca2ae5ebc..ad537b0ad4 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -65,6 +65,8 @@ namespace MWDialogue virtual MWWorld::Ptr getActor() const; ///< Return the actor the player is currently talking to. + virtual bool checkServiceRefused (); + //calbacks for the GUI virtual void keywordSelected (const std::string& keyword); virtual void goodbyeSelected(); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 10740794ea..906e30c768 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -121,7 +121,7 @@ bool MWDialogue::Filter::testSelectStructs (const ESM::DialInfo& info) const return true; } -bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const +bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert) const { bool isCreature = (mActor.getTypeName() != typeid (ESM::NPC).name()); @@ -129,8 +129,9 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info) const return true; int actorDisposition = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mActor); - - return actorDisposition >= info.mData.mDisposition; + // For service refusal, the disposition check is inverted. However, a value of 0 still means "always succeed". + return invert ? (info.mData.mDisposition == 0 || actorDisposition < info.mData.mDisposition) + : (actorDisposition >= info.mData.mDisposition); } bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const @@ -570,7 +571,7 @@ const ESM::DialInfo* MWDialogue::Filter::search (const ESM::Dialogue& dialogue, } std::vector MWDialogue::Filter::list (const ESM::Dialogue& dialogue, - bool fallbackToInfoRefusal, bool searchAll) const + bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition) const { std::vector infos; @@ -582,7 +583,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue { if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter)) { - if (testDisposition (*iter)) { + if (testDisposition (*iter, invertDisposition)) { infos.push_back(&*iter); if (!searchAll) break; @@ -604,7 +605,7 @@ std::vector MWDialogue::Filter::list (const ESM::Dialogue for (std::vector::const_iterator iter = infoRefusalDialogue.mInfo.begin(); iter!=infoRefusalDialogue.mInfo.end(); ++iter) - if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter)) { + if (testActor (*iter) && testPlayer (*iter) && testSelectStructs (*iter) && testDisposition(*iter, invertDisposition)) { infos.push_back(&*iter); if (!searchAll) break; diff --git a/apps/openmw/mwdialogue/filter.hpp b/apps/openmw/mwdialogue/filter.hpp index 069bf6353d..5c6d092ad9 100644 --- a/apps/openmw/mwdialogue/filter.hpp +++ b/apps/openmw/mwdialogue/filter.hpp @@ -30,8 +30,8 @@ namespace MWDialogue bool testSelectStructs (const ESM::DialInfo& info) const; ///< Are all select structs matching? - bool testDisposition (const ESM::DialInfo& info) const; - ///< Is the actor disposition toward the player high enough? + bool testDisposition (const ESM::DialInfo& info, bool invert=false) const; + ///< Is the actor disposition toward the player high enough (or low enough, if \a invert is true)? bool testSelectStruct (const SelectWrapper& select) const; @@ -54,7 +54,7 @@ namespace MWDialogue Filter (const MWWorld::Ptr& actor, int choice, bool talkedToPlayer); std::vector list (const ESM::Dialogue& dialogue, - bool fallbackToInfoRefusal, bool searchAll) const; + bool fallbackToInfoRefusal, bool searchAll, bool invertDisposition=false) const; const ESM::DialInfo* search (const ESM::Dialogue& dialogue, const bool fallbackToInfoRefusal) const; ///< Get a matching response for the requested dialogue. diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index cdcbfc4d18..c500cd1747 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -241,40 +241,42 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (topic == gmst.find("sBarter")->getString()) - { - /// \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(mPtr); - } if (topic == gmst.find("sPersuasion")->getString()) { mPersuasionDialog.setVisible(true); } - else if (topic == gmst.find("sSpells")->getString()) + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); + if (topic == gmst.find("sBarter")->getString()) + { + mWindowManager.pushGuiMode(GM_Barter); + mWindowManager.getTradeWindow()->startTrade(mPtr); + } + else if (topic == gmst.find("sSpells")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellBuying); + mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + mWindowManager.pushGuiMode(GM_Travel); + mWindowManager.getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_SpellCreation); + mWindowManager.startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + mWindowManager.pushGuiMode(GM_Enchanting); + mWindowManager.startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + mWindowManager.pushGuiMode(GM_Training); + mWindowManager.startTraining (mPtr); + } } } } From e8b08326dc47d39faf4da2119ee2681818ed2db0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 20:52:05 +0100 Subject: [PATCH 0065/1537] Corrected Id, Race, Class, Faction and Cell select functions to do the exact opposite as before. That is how they are displayed in the CS, anyway. --- apps/openmw/mwdialogue/filter.cpp | 20 ++++++++++---------- apps/openmw/mwdialogue/selectwrapper.cpp | 14 +++++++------- apps/openmw/mwdialogue/selectwrapper.hpp | 10 +++++----- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 906e30c768..d3405b2b26 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -413,25 +413,25 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return false; - case SelectWrapper::Function_Id: + case SelectWrapper::Function_NotId: - return select.getName()==Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); + return select.getName()!=Misc::StringUtils::lowerCase (MWWorld::Class::get (mActor).getId (mActor)); - case SelectWrapper::Function_Faction: + case SelectWrapper::Function_NotFaction: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mFaction)!=select.getName(); - case SelectWrapper::Function_Class: + case SelectWrapper::Function_NotClass: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mClass)!=select.getName(); - case SelectWrapper::Function_Race: + case SelectWrapper::Function_NotRace: - return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.get()->mBase->mRace)!=select.getName(); - case SelectWrapper::Function_Cell: + case SelectWrapper::Function_NotCell: - return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)==select.getName(); + return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)!=select.getName(); case SelectWrapper::Function_SameGender: diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 9d705f6bec..77930ae423 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -112,11 +112,11 @@ MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() con case '4': return Function_Journal; case '5': return Function_Item; case '6': return Function_Dead; - case '7': return Function_Id; - case '8': return Function_Faction; - case '9': return Function_Class; - case 'A': return Function_Race; - case 'B': return Function_Cell; + case '7': return Function_NotId; + case '8': return Function_NotFaction; + case '9': return Function_NotClass; + case 'A': return Function_NotRace; + case 'B': return Function_NotCell; case 'C': return Function_Local; } @@ -219,7 +219,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function booleanFunctions[] = { Function_False, - Function_Id, Function_Faction, Function_Class, Function_Race, Function_Cell, + Function_NotId, Function_NotFaction, Function_NotClass, Function_NotRace, Function_NotCell, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, Function_PcExpelled, @@ -259,7 +259,7 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = { - Function_Faction, SelectWrapper::Function_Class, SelectWrapper::Function_Race, + Function_NotFaction, SelectWrapper::Function_NotClass, SelectWrapper::Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcSkill, Function_PcExpelled, diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index b77ed7985a..c27339afa0 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -17,11 +17,11 @@ namespace MWDialogue Function_Journal, Function_Item, Function_Dead, - Function_Id, - Function_Faction, - Function_Class, - Function_Race, - Function_Cell, + Function_NotId, + Function_NotFaction, + Function_NotClass, + Function_NotRace, + Function_NotCell, Function_Local, Function_Global, Function_SameGender, Function_SameRace, Function_SameFaction, From 1666bc77407deb0a89657a8e73d6f7dce93417e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 22:53:33 +0100 Subject: [PATCH 0066/1537] Armor rating --- apps/openmw/mwbase/mechanicsmanager.hpp | 5 +- apps/openmw/mwgui/inventorywindow.cpp | 5 ++ .../mwmechanics/mechanicsmanagerimp.cpp | 49 +++++++++++++++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 3 ++ files/mygui/openmw_inventory_window.layout | 1 - 5 files changed, 61 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index b8733259ff..6cb7c69188 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -82,7 +82,10 @@ namespace MWBase virtual int getDerivedDisposition(const MWWorld::Ptr& ptr) = 0; ///< Calculate the diposition of an NPC toward the player. - + + virtual float getArmorRating (const MWWorld::Ptr& ptr) = 0; + ///< Calculate the combined armor rating of an NPC. + virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index ab7615c0ef..2caed79728 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -13,6 +13,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/containerstore.hpp" #include "../mwworld/class.hpp" @@ -50,6 +51,7 @@ namespace MWGui getWidget(mFilterMisc, "MiscButton"); getWidget(mLeftPane, "LeftPane"); getWidget(mRightPane, "RightPane"); + getWidget(mArmorRating, "ArmorRating"); mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); @@ -288,6 +290,9 @@ namespace MWGui mPreview.update (size.width, size.height); mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); mAvatarImage->setImageTexture("CharacterPreview"); + + mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + + boost::lexical_cast(static_cast(MWBase::Environment::get().getMechanicsManager()->getArmorRating(mPtr)))); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c9e4c77eaf..c19b84cd80 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -2,6 +2,7 @@ #include "mechanicsmanagerimp.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/inventorystore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -668,4 +669,52 @@ namespace MWMechanics mActors.skipAnimation(ptr); } + float MechanicsManager::getArmorRating(const MWWorld::Ptr &ptr) + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + int ratings[MWWorld::InventoryStore::Slots]; + + int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); + float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); + float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); + + for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(i); + if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) + { + // unarmored + ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + } + else + { + MWWorld::LiveCellRef *ref = + it->get(); + + int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); + int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); + + if (ref->mBase->mData.mWeight == 0) + ratings[i] = ref->mBase->mData.mArmor; + else + ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + } + + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(3).mMagnitude; + + return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] + + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] + + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] + ) * 0.1 + + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) + * 0.05 + + shield; + } + } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5ad8705719..2e09c5f8e5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,6 +88,9 @@ namespace MWMechanics virtual int getDerivedDisposition(const MWWorld::Ptr& ptr); ///< Calculate the diposition of an NPC toward the player. + virtual float getArmorRating (const MWWorld::Ptr& ptr); + ///< Calculate the combined armor rating of an NPC. + virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 88cc5638d3..41bd40f923 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -17,7 +17,6 @@ - From dd57eabc3ef9475f2c9b7e2aadba5da8d519cd33 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 16 Mar 2013 23:28:26 +0100 Subject: [PATCH 0067/1537] Better use an enum for magic effect IDs --- apps/openmw/mwclass/creature.cpp | 4 +- apps/openmw/mwclass/npc.cpp | 4 +- apps/openmw/mwdialogue/filter.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 9 +- .../mwmechanics/mechanicsmanagerimp.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/esm/loadmgef.hpp | 152 ++++++++++++++++++ 8 files changed, 164 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 19f327dcbb..1b6212a238 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -203,9 +203,9 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).mMagnitude; if (weight<0) weight = 0; diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 2ed285a813..d931b9e2ea 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -471,9 +471,9 @@ namespace MWClass const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); - weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (8)).mMagnitude; // feather + weight -= stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Feather)).mMagnitude; - weight += stats.getMagicEffects().get (MWMechanics::EffectKey (7)).mMagnitude; // burden + weight += stats.getMagicEffects().get (MWMechanics::EffectKey (ESM::MagicEffect::Burden)).mMagnitude; if (weight<0) weight = 0; diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index d3405b2b26..7b5f354a23 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -459,7 +459,7 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co case SelectWrapper::Function_PcCorprus: return MWWorld::Class::get (player).getCreatureStats (player). - getMagicEffects().get (132).mMagnitude!=0; + getMagicEffects().get (ESM::MagicEffect::Corprus).mMagnitude!=0; case SelectWrapper::Function_PcExpelled: { diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 794a9ab55f..6e914a669b 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -159,7 +159,7 @@ namespace MWGui float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; - bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(136)).mMagnitude > 0); + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9632bdf769..efbda83ee4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -71,7 +71,7 @@ namespace MWMechanics int endurance = creatureStats.getAttribute(5).getBase(); double magickaFactor = - creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5; + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyMaximumMagicka)).mMagnitude * 0.1 + 0.5; DynamicStat health = creatureStats.getHealth(); health.setBase (static_cast (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ()); @@ -92,8 +92,7 @@ namespace MWMechanics if (duration == 3600) { - // stunted magicka - bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(136)).mMagnitude > 0; + bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); @@ -140,9 +139,9 @@ namespace MWMechanics for (int i=0; i<8; ++i) { int modifier = - creatureStats.getMagicEffects().get (EffectKey (79, i)).mMagnitude; + creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::FortifyAttribute, i)).mMagnitude; - modifier -= creatureStats.getMagicEffects().get (EffectKey (17, i)).mMagnitude; + modifier -= creatureStats.getMagicEffects().get (EffectKey (ESM::MagicEffect::DrainAttribute, i)).mMagnitude; creatureStats.getAttribute(i).setModifier (modifier); } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c19b84cd80..ac470fbbac 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -705,7 +705,7 @@ namespace MWMechanics } } - float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(3).mMagnitude; + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a23aae972..a8b4135187 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1259,7 +1259,7 @@ namespace MWWorld World::isFlying(const MWWorld::Ptr &ptr) const { const MWWorld::Class &cls = MWWorld::Class::get(ptr); - if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(10/*levitate*/)).mMagnitude > 0) + if(cls.isActor() && cls.getCreatureStats(ptr).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Levitate)).mMagnitude > 0) return true; return false; } diff --git a/components/esm/loadmgef.hpp b/components/esm/loadmgef.hpp index 93c59f9cbe..7efc17aec5 100644 --- a/components/esm/loadmgef.hpp +++ b/components/esm/loadmgef.hpp @@ -66,6 +66,158 @@ struct MagicEffect void load(ESMReader &esm); void save(ESMWriter &esm); + + + enum Effects + { + WaterBreathing = 0, + SwiftSwim = 1, + WaterWalking = 2, + Shield = 3, + FireShield = 4, + LightningShield = 5, + FrostShield = 6, + Burden = 7, + Feather = 8, + Jump = 9, + Levitate = 10, + SlowFall = 11, + Lock = 12, + Open = 13, + FireDamage = 14, + ShockDamage = 15, + FrostDamage = 16, + DrainAttribute = 17, + DrainHealth = 18, + DrainMagicka = 19, + DrainFatigue = 20, + DrainSkill = 21, + DamageAttribute = 22, + DamageHealth = 23, + DamageMagicka = 24, + DamageFatigue = 25, + DamageSkill = 26, + Poison = 27, + WeaknessToFire = 28, + WeaknessToFrost = 29, + WeaknessToShock = 30, + WeaknessToMagicka = 31, + WeaknessToCommonDisease = 32, + WeaknessToBlightDisease = 33, + WeaknessToCorprusDisease = 34, + WeaknessToPoison = 35, + WeaknessToNormalWeapons = 36, + DisintegrateWeapon = 37, + DisintegrateArmor = 38, + Invisibility = 39, + Chameleon = 40, + Light = 41, + Sanctuary = 42, + NightEye = 43, + Charm = 44, + Paralyze = 45, + Silence = 46, + Blind = 47, + Sound = 48, + CalmHumanoid = 49, + CalmCreature = 50, + FrenzyHumanoid = 51, + FrenzyCreature = 52, + DemoralizeHumanoid = 53, + DemoralizeCreature = 54, + RallyHumanoid = 55, + RallyCreature = 56, + Dispel = 57, + Soultrap = 58, + Telekinesis = 59, + Mark = 60, + Recall = 61, + DivineIntervention = 62, + AlmsiviIntervention = 63, + DetectAnimal = 64, + DetectEnchantment = 65, + DetectKey = 66, + SpellAbsorption = 67, + Reflect = 68, + CureCommonDisease = 69, + CureBlightDisease = 70, + CureCorprusDisease = 71, + CurePoison = 72, + CureParalyzation = 73, + RestoreAttribute = 74, + RestoreHealth = 75, + RestoreMagicka = 76, + RestoreFatigue = 77, + RestoreSkill = 78, + FortifyAttribute = 79, + FortifyHealth = 80, + FortifyMagicka= 81, + FortifyFatigue = 82, + FortifySkill = 83, + FortifyMaximumMagicka = 84, + AbsorbAttribute = 85, + AbsorbHealth = 86, + AbsorbMagicka = 87, + AbsorbFatigue = 88, + AbsorbSkill = 89, + ResistFire = 90, + ResistFrost = 91, + ResistShock = 92, + ResistMagicka = 93, + ResistCommonDisease = 94, + ResistBlightDisease = 95, + ResistCorprusDisease = 96, + ResistPoison = 97, + ResistNormalWeapons = 98, + ResistParalysis = 99, + RemoveCurse = 100, + TurnUndead = 101, + SummonScamp = 102, + SummonClannfear = 103, + SummonDaedroth = 104, + SummonDremora = 105, + SummonAncestralGhost = 106, + SummonSkeletalMinion = 107, + SummonBonewalker = 108, + SummonGreaterBonewalker = 109, + SummonBonelord = 110, + SummonWingedTwilight = 111, + SummonHunger = 112, + SummonGoldenSaint = 113, + SummonFlameAtronach = 114, + SummonFrostAtronach = 115, + SummonStormAtronach = 116, + FortifyAttack = 117, + CommandCreature = 118, + CommandHumanoid = 119, + BoundDagger = 120, + BoundLongsword = 121, + BoundMace = 122, + BoundBattleAxe = 123, + BoundSpear = 124, + BoundLongbow = 125, + ExtraSpell = 126, + BoundCuirass = 127, + BoundHelm = 128, + BoundBoots = 129, + BoundShield = 130, + BoundGloves = 131, + Corprus = 132, + Vampirism = 133, + SummonCenturionSphere = 134, + SunDamage = 135, + StuntedMagicka = 136, + + // Tribunal only + SummonFabricant = 137, + + // Bloodmoon only + SummonWolf = 138, + SummonBear = 139, + SummonBonewolf = 140, + SummonCreature04 = 141, + SummonCreature05 = 142 + }; }; } #endif From c07b3ea61d96b918be9df6cdd23df9691e52ee77 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Mar 2013 04:20:30 +0100 Subject: [PATCH 0068/1537] Text defines for npc race, class, and faction should use the translated name --- apps/openmw/mwscript/interpretercontext.cpp | 9 ++++++--- apps/openmw/mwscript/interpretercontext.hpp | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index c74e3f1633..cad143c469 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -215,19 +215,22 @@ namespace MWScript std::string InterpreterContext::getNPCRace() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mRace; + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mRace); + return race->mName; } std::string InterpreterContext::getNPCClass() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mClass; + const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mClass); + return class_->mName; } std::string InterpreterContext::getNPCFaction() const { ESM::NPC npc = *mReference.get()->mBase; - return npc.mFaction; + const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get().find(npc.mFaction); + return faction->mName; } std::string InterpreterContext::getNPCRank() const diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index f0b2758d9e..9c7b443ae1 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -89,7 +89,7 @@ namespace MWScript virtual std::string getNPCClass() const; virtual std::string getNPCFaction() const; - + virtual std::string getNPCRank() const; virtual std::string getPCName() const; From ea7f386e7d5d28958f004e70820f5e125d32e766 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 13:50:15 +0100 Subject: [PATCH 0069/1537] Access to Fallback via getFallback --- apps/openmw/mwbase/world.hpp | 3 ++- apps/openmw/mwgui/charactercreation.cpp | 12 ++++++------ apps/openmw/mwgui/levelupdialog.cpp | 5 +++-- apps/openmw/mwworld/worldimp.cpp | 10 +++++----- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 17 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 642291eefb..1d6b290c80 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -46,6 +46,7 @@ namespace MWRender namespace MWWorld { + class Fallback; class CellStore; class Player; class LocalScripts; @@ -103,7 +104,7 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual std::string getFallback (const std::string& key) const = 0; + virtual MWWorld::Fallback *getFallback () = 0; virtual MWWorld::Player& getPlayer() = 0; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index b98fd2bd9f..5bc89fbd1b 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -12,6 +12,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwworld/fallback.hpp" namespace { @@ -23,14 +24,13 @@ namespace }; const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer - Step sGenerateClassSteps(int number) { - MWBase::World *world = MWBase::Environment::get().getWorld(); number++; - Step step = {world->getFallback("Question_"+boost::lexical_cast(number)+"_Question"), - {world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerOne"), - world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), - world->getFallback("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, + MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), + {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), + fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), + fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerThree")}, "vo\\misc\\chargen qa"+boost::lexical_cast(number)+".wav" }; return step; diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 9473f48b4e..f0a3858084 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -9,6 +9,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" #include "../mwworld/esmstore.hpp" +#include "../mwworld/fallback.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" @@ -138,9 +139,9 @@ namespace MWGui std::string levelupdescription; if(level>20) - levelupdescription=world->getFallback("Level_Up_Default"); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Default"); else - levelupdescription=world->getFallback("Level_Up_Level"+boost::lexical_cast(level)); + levelupdescription=world->getFallback()->getFallbackString("Level_Up_Level"+boost::lexical_cast(level)); mLevelDescription->setCaption (levelupdescription); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a23aae972..ee41afc58a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -154,11 +154,6 @@ namespace MWWorld mRendering->skyDisable(); } - std::string World::getFallback (const std::string& key) const - { - return mFallback.getFallbackString(key); - } - World::World (OEngine::Render::OgreRenderer& renderer, const Files::Collections& fileCollections, const std::vector& master, const std::vector& plugins, @@ -267,6 +262,11 @@ namespace MWWorld return 0; } + MWWorld::Fallback *World::getFallback () + { + return &mFallback; + } + Ptr::CellStore *World::getExterior (int x, int y) { return mCells.getExterior (x, y); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 526e68a77a..d2db653db1 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -133,7 +133,7 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual std::string getFallback (const std::string& key) const; + virtual Fallback *getFallback (); virtual Player& getPlayer(); From 6165cd2c6b7fd0deafe391579e4109e3aa5197a4 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 14:22:30 +0100 Subject: [PATCH 0070/1537] Moons fallbacks partially implemented --- apps/openmw/mwrender/sky.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 604ad50d22..ff2ef2a4f7 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -21,6 +21,8 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/fallback.hpp" + #include "renderconst.hpp" #include "renderingmanager.hpp" @@ -266,11 +268,12 @@ void SkyManager::create() mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); - mSecunda = new Moon("secunda_texture", 0.5, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + mSecunda = new Moon("secunda_texture", /*0.5*/fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); - mMasser = new Moon("masser_texture", 0.75, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); + mMasser = new Moon("masser_texture", /*0.75*/fallback->getFallbackFloat("Moons_Masser_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mMasser->setRenderQueue(RQG_SkiesEarly+3); mMasser->setType(Moon::Type_Masser); @@ -368,7 +371,7 @@ int SkyManager::getSecundaPhase() const void SkyManager::update(float duration) { if (!mEnabled) return; - + MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mCamera->getParentSceneNode ()->needUpdate (); mRootNode->setPosition(mCamera->getDerivedPosition()); @@ -381,7 +384,7 @@ void SkyManager::update(float duration) mMasser->setPhase( static_cast( (int) ((mDay % 32)/4.f)) ); mSecunda->setPhase ( static_cast( (int) ((mDay % 32)/4.f)) ); - mSecunda->setColour ( mMoonRed ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1,1,1,1)); + mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1)); mMasser->setColour (ColourValue(1,1,1,1)); if (mSunEnabled) From 1369090a80fac639095e8ff358f7892332ba1038 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 14:50:02 +0100 Subject: [PATCH 0071/1537] More moons fallbacks, minor weather fixes --- apps/openmw/mwworld/weather.cpp | 72 +++++++-------------------------- 1 file changed, 14 insertions(+), 58 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 867e910fe3..ea0270197f 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -110,60 +110,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa /* 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; + setFallbackWeather(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; + setFallbackWeather(blizzard,"blizzard") */ } @@ -471,20 +423,24 @@ void WeatherManager::update(float duration) 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) + float secunda_angle_fade; + float secunda_end_angle=mFallback->getFallbackFloat("Moons_Secunda_Fade_End_Angle"); + float secunda_start_angle=mFallback->getFallbackFloat("Moons_Secunda_Fade_Start_Angle"); + if (angle >= secunda_end_angle && angle <= secunda_start_angle) + secunda_angle_fade = (angle-secunda_end_angle)/20.f; + else if (angle < secunda_end_angle) 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) + float masser_angle_fade; + float masser_end_angle=mFallback->getFallbackFloat("Moons_Masser_Fade_End_Angle"); + float masser_start_angle=mFallback->getFallbackFloat("Moons_Masser_Fade_Start_Angle"); + if (angle >= masser_end_angle && angle <= masser_start_angle) + masser_angle_fade = (angle-masser_end_angle)/10.f; + else if (angle < masser_end_angle) masser_angle_fade = 0.f; else masser_angle_fade = 1.f; From 46bde604f9fe4dec594d7e087d8b7956f66fc2a4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 17 Mar 2013 17:13:25 +0100 Subject: [PATCH 0072/1537] Issue #601: unary minus was interpreted as binary minus when used in an argument list without comma --- components/compiler/exprparser.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 027f3de712..94240c5eb9 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -603,8 +603,8 @@ namespace Compiler switch (code) { - case Scanner::S_plus: pushBinaryOperator ('+'); return true; - case Scanner::S_minus: pushBinaryOperator ('-'); return true; + case Scanner::S_plus: c = '+'; break; + case Scanner::S_minus: c = '-'; break; case Scanner::S_mult: pushBinaryOperator ('*'); return true; case Scanner::S_div: pushBinaryOperator ('/'); return true; case Scanner::S_cmpEQ: c = 'e'; break; From f3fd3a7691a4e13a4152dfa1c5fe520c2bffd91e Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 19:36:14 +0100 Subject: [PATCH 0073/1537] Much more moons fallbacks --- apps/openmw/mwworld/weather.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ea0270197f..f7e8566751 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -415,13 +415,28 @@ void WeatherManager::update(float duration) 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; + float secunda_hour_fade; + float secunda_fadeout_start=mFallback->getFallbackFloat("Moons_Secunda_Fade_Out_Start"); + float secunda_fadein_start=mFallback->getFallbackFloat("Moons_Secunda_Fade_In_Start"); + float secunda_fadein_finish=mFallback->getFallbackFloat("Moons_Secunda_Fade_In_Finish"); + + if (mHour >= secunda_fadeout_start && mHour <= secunda_fadein_start) + secunda_hour_fade = 1-(mHour-secunda_fadeout_start)/3.f; + else if (mHour >= secunda_fadein_start && mHour <= secunda_fadein_finish) + secunda_hour_fade = mHour-secunda_fadein_start; else - hour_fade = 1; + secunda_hour_fade = 1; + + float masser_hour_fade; + float masser_fadeout_start=mFallback->getFallbackFloat("Moons_Masser_Fade_Out_Start"); + float masser_fadein_start=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Start"); + float masser_fadein_finish=mFallback->getFallbackFloat("Moons_Masser_Fade_In_Finish"); + if (mHour >= masser_fadeout_start && mHour <= masser_fadein_start) + masser_hour_fade = 1-(mHour-masser_fadeout_start)/3.f; + else if (mHour >= masser_fadein_start && mHour <= masser_fadein_finish) + masser_hour_fade = mHour-masser_fadein_start; + else + masser_hour_fade = 1; float angle = moonHeight*90.f; @@ -445,8 +460,8 @@ void WeatherManager::update(float duration) else masser_angle_fade = 1.f; - masser_angle_fade *= hour_fade; - secunda_angle_fade *= hour_fade; + masser_angle_fade *= masser_hour_fade; + secunda_angle_fade *= secunda_hour_fade; mRendering->getSkyManager()->setMasserFade(masser_angle_fade); mRendering->getSkyManager()->setSecundaFade(secunda_angle_fade); From 5922637c58bbf58378104e52f04ac31443b5ef15 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 17 Mar 2013 20:12:26 +0100 Subject: [PATCH 0074/1537] Unblocked Solstheim weather that should work now. --- apps/openmw/mwworld/weather.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index f7e8566751..5aaf40dc55 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -107,16 +107,14 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa blight.mAmbientLoopSoundID = "blight"; setFallbackWeather(blight,"blight"); - /* Weather snow; snow.mCloudTexture = "tx_bm_sky_snow.dds"; - setFallbackWeather(snow, "snow") + setFallbackWeather(snow, "snow"); Weather blizzard; blizzard.mCloudTexture = "tx_bm_sky_blizzard.dds"; blizzard.mAmbientLoopSoundID = "BM Blizzard"; - setFallbackWeather(blizzard,"blizzard") - */ + setFallbackWeather(blizzard,"blizzard"); } void WeatherManager::setWeather(const String& weather, bool instant) From c66675b5997f104b2de753fecb96bfbc82e0def5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Mar 2013 22:28:28 +0100 Subject: [PATCH 0075/1537] Fix the 'Take all' button taking equipped items when stealing --- apps/openmw/mwgui/container.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 2b80003127..e476865433 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -683,12 +683,18 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + std::vector equippedItems = getEquippedItems(); + 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 (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() + && !mDisplayEquippedItems) + continue; + playerStore.add(*iter); if (i==0) @@ -698,11 +704,11 @@ void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); } + iter->getRefData().setCount(0); + ++i; } - containerStore.clear(); - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } } From 95e1cdc07ddd1443522695f20617b5c110169ea7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 17 Mar 2013 22:29:12 +0100 Subject: [PATCH 0076/1537] Move getArmorRating to MWWorld::Class. --- apps/openmw/mwbase/mechanicsmanager.hpp | 3 -- apps/openmw/mwclass/creature.cpp | 6 +++ apps/openmw/mwclass/creature.hpp | 3 ++ apps/openmw/mwclass/npc.cpp | 49 +++++++++++++++++++ apps/openmw/mwclass/npc.hpp | 3 ++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- .../mwmechanics/mechanicsmanagerimp.cpp | 48 ------------------ .../mwmechanics/mechanicsmanagerimp.hpp | 3 -- apps/openmw/mwworld/class.cpp | 7 ++- apps/openmw/mwworld/class.hpp | 3 ++ 10 files changed, 71 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 6cb7c69188..020647744b 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -83,9 +83,6 @@ namespace MWBase virtual int getDerivedDisposition(const MWWorld::Ptr& ptr) = 0; ///< Calculate the diposition of an NPC toward the player. - virtual float getArmorRating (const MWWorld::Ptr& ptr) = 0; - ///< Calculate the combined armor rating of an NPC. - virtual int countDeaths (const std::string& id) const = 0; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1b6212a238..1097f8f29c 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -191,6 +191,12 @@ namespace MWClass return info; } + float Creature::getArmorRating (const MWWorld::Ptr& ptr) const + { + /// \todo add Shield magic effect magnitude here, controlled by a GMST (Vanilla vs MCP behaviour) + return 0.f; + } + float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index a96c18a8c5..ea356165eb 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -54,6 +54,9 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual bool isEssential (const MWWorld::Ptr& ptr) const; ///< Is \a ptr essential? (i.e. may losing \a ptr make the game unwinnable) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d931b9e2ea..a5319ada07 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -505,6 +505,55 @@ namespace MWClass stats.useSkill (skill, *class_, usageType); } + float Npc::getArmorRating (const MWWorld::Ptr& ptr) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + int ratings[MWWorld::InventoryStore::Slots]; + + int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); + float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); + float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); + int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); + + for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(i); + if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) + { + // unarmored + ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); + } + else + { + MWWorld::LiveCellRef *ref = + it->get(); + + int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); + int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); + + if (ref->mBase->mData.mWeight == 0) + ratings[i] = ref->mBase->mData.mArmor; + else + ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; + } + } + + float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; + + return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 + + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] + + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] + + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] + ) * 0.1 + + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) + * 0.05 + + shield; + } + + void Npc::adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const { y = 0; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 0ca6a8d69e..0f61fc8c91 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -104,6 +104,9 @@ namespace MWClass ///< Returns total weight of objects inside this object (including modifications from magic /// effects). Throws an exception, if the object can't hold other objects. + virtual float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const; ///< Apply \a id on \a ptr. diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 2caed79728..29966bd08a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -292,7 +292,7 @@ namespace MWGui mAvatarImage->setImageTexture("CharacterPreview"); mArmorRating->setCaptionWithReplacing ("#{sArmor}: " - + boost::lexical_cast(static_cast(MWBase::Environment::get().getMechanicsManager()->getArmorRating(mPtr)))); + + boost::lexical_cast(static_cast(MWWorld::Class::get(mPtr).getArmorRating(mPtr)))); } void InventoryWindow::pickUpObject (MWWorld::Ptr object) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index ac470fbbac..32fa58980d 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -669,52 +669,4 @@ namespace MWMechanics mActors.skipAnimation(ptr); } - float MechanicsManager::getArmorRating(const MWWorld::Ptr &ptr) - { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - - int ratings[MWWorld::InventoryStore::Slots]; - - int iBaseArmorSkill = gmst.find("iBaseArmorSkill")->getInt(); - float fUnarmoredBase1 = gmst.find("fUnarmoredBase1")->getFloat(); - float fUnarmoredBase2 = gmst.find("fUnarmoredBase2")->getFloat(); - int unarmoredSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(ESM::Skill::Unarmored).getModified(); - - for (int i = 0; i < MWWorld::InventoryStore::Slots; ++i) - { - MWWorld::ContainerStoreIterator it = invStore.getSlot(i); - if (it == invStore.end() || it->getTypeName() != typeid(ESM::Armor).name()) - { - // unarmored - ratings[i] = (fUnarmoredBase1 * unarmoredSkill) * (fUnarmoredBase2 * unarmoredSkill); - } - else - { - MWWorld::LiveCellRef *ref = - it->get(); - - int armorSkillType = MWWorld::Class::get(*it).getEquipmentSkill(*it); - int armorSkill = MWWorld::Class::get(ptr).getNpcStats(ptr).getSkill(armorSkillType).getModified(); - - if (ref->mBase->mData.mWeight == 0) - ratings[i] = ref->mBase->mData.mArmor; - else - ratings[i] = ref->mBase->mData.mArmor * armorSkill / iBaseArmorSkill; - } - } - - float shield = MWWorld::Class::get(ptr).getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Shield).mMagnitude; - - return ratings[MWWorld::InventoryStore::Slot_Cuirass] * 0.3 - + (ratings[MWWorld::InventoryStore::Slot_CarriedLeft] + ratings[MWWorld::InventoryStore::Slot_Helmet] - + ratings[MWWorld::InventoryStore::Slot_Greaves] + ratings[MWWorld::InventoryStore::Slot_Boots] - + ratings[MWWorld::InventoryStore::Slot_LeftPauldron] + ratings[MWWorld::InventoryStore::Slot_RightPauldron] - ) * 0.1 - + (ratings[MWWorld::InventoryStore::Slot_LeftGauntlet] + MWWorld::InventoryStore::Slot_RightGauntlet) - * 0.05 - + shield; - } - } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 2e09c5f8e5..5ad8705719 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -88,9 +88,6 @@ namespace MWMechanics virtual int getDerivedDisposition(const MWWorld::Ptr& ptr); ///< Calculate the diposition of an NPC toward the player. - virtual float getArmorRating (const MWWorld::Ptr& ptr); - ///< Calculate the combined armor rating of an NPC. - virtual int countDeaths (const std::string& id) const; ///< Return the number of deaths for actors with the given ID. diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 71b24b65dc..985d35d45e 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -167,11 +167,16 @@ namespace MWWorld return false; } - bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const + bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const { return false; } + float Class::getArmorRating (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error("Class does not support armor rating"); + } + 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 1a6a16ca07..53dbeff862 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -215,6 +215,9 @@ namespace MWWorld ///< 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 float getArmorRating (const MWWorld::Ptr& ptr) const; + ///< @return combined armor rating of this actor + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; ///< Return name of inventory icon. From 08f6d04960f426d80e42e5b9e4c1251ee58fb467 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 08:29:40 +0100 Subject: [PATCH 0077/1537] constness fixes --- apps/openmw/mwbase/world.hpp | 6 +++--- apps/openmw/mwgui/charactercreation.cpp | 2 +- apps/openmw/mwrender/sky.cpp | 4 ++-- apps/openmw/mwworld/worldimp.cpp | 2 +- apps/openmw/mwworld/worldimp.hpp | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 1d6b290c80..f3b817e516 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -104,7 +104,7 @@ namespace MWBase virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches) = 0; - virtual MWWorld::Fallback *getFallback () = 0; + virtual const MWWorld::Fallback *getFallback () const = 0; virtual MWWorld::Player& getPlayer() = 0; @@ -139,7 +139,7 @@ namespace MWBase virtual char getGlobalVariableType (const std::string& name) const = 0; ///< Return ' ', if there is no global variable with this name. - + virtual std::vector getGlobals () const = 0; virtual std::string getCurrentCellName() const = 0; @@ -296,7 +296,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual void renderPlayer() = 0; - + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 5bc89fbd1b..0cc12170ac 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -26,7 +26,7 @@ namespace const ESM::Class::Specialization mSpecializations[3]={ESM::Class::Combat, ESM::Class::Magic, ESM::Class::Stealth}; // The specialization for each answer Step sGenerateClassSteps(int number) { number++; - MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); Step step = {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_Question"), {fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerOne"), fallback->getFallbackString("Question_"+boost::lexical_cast(number)+"_AnswerTwo"), diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index ff2ef2a4f7..94af3521b3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -268,7 +268,7 @@ void SkyManager::create() mLightning->setVisible (false); mLightning->setDiffuseColour (ColourValue(3,3,3)); - MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mSecunda = new Moon("secunda_texture", /*0.5*/fallback->getFallbackFloat("Moons_Secunda_Size")/100, Vector3(-0.4, 0.4, 0.5), mRootNode, "openmw_moon"); mSecunda->setType(Moon::Type_Secunda); mSecunda->setRenderQueue(RQG_SkiesEarly+4); @@ -371,7 +371,7 @@ int SkyManager::getSecundaPhase() const void SkyManager::update(float duration) { if (!mEnabled) return; - MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); mCamera->getParentSceneNode ()->needUpdate (); mRootNode->setPosition(mCamera->getDerivedPosition()); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 63e0f14d63..0a874513c3 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -262,7 +262,7 @@ namespace MWWorld return 0; } - MWWorld::Fallback *World::getFallback () + const MWWorld::Fallback *World::getFallback() const { return &mFallback; } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index d2db653db1..24565029fc 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -133,7 +133,7 @@ namespace MWWorld virtual void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); - virtual Fallback *getFallback (); + virtual const Fallback *getFallback() const; virtual Player& getPlayer(); From 61cb0f98a60718d76c1e12f81c4b16a0c8930f71 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 10:46:45 +0100 Subject: [PATCH 0078/1537] keep track of death events --- apps/openmw/mwmechanics/creaturestats.cpp | 18 +++++++++++++++++- apps/openmw/mwmechanics/creaturestats.hpp | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 4be5d55b22..19d2080211 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -10,7 +10,8 @@ namespace MWMechanics { CreatureStats::CreatureStats() - : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mFriendlyHits (0), mTalkedTo (false), mAlarmed (false), + : mLevel (0), mLevelHealthBonus(0.f), mDead (false), mDied (false), mFriendlyHits (0), + mTalkedTo (false), mAlarmed (false), mAttacked (false), mHostile (false) { for (int i=0; i<4; ++i) @@ -167,7 +168,12 @@ namespace MWMechanics mDynamic[index] = value; if (index==0 && mDynamic[index].getCurrent()<1) + { + if (!mDead) + mDied = true; + mDead = true; + } } void CreatureStats::setLevel(int level) @@ -196,6 +202,16 @@ namespace MWMechanics return mDead; } + bool CreatureStats::hasDied() const + { + return mDied; + } + + void CreatureStats::clearHasDied() + { + mDied = false; + } + void CreatureStats::resurrect() { if (mDead) diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 3375c1af83..63de13d0d4 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -28,6 +28,7 @@ namespace MWMechanics AiSequence mAiSequence; float mLevelHealthBonus; bool mDead; + bool mDied; int mFriendlyHits; bool mTalkedTo; bool mAlarmed; @@ -100,6 +101,10 @@ namespace MWMechanics bool isDead() const; + bool hasDied() const; + + void clearHasDied(); + void resurrect(); bool hasCommonDisease() const; From fd2c07a6f47b26469d01d05b7a284aa87f9caef2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 10:54:47 +0100 Subject: [PATCH 0079/1537] delete death events on adding an actor to the scene --- apps/openmw/mwmechanics/actors.cpp | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index efbda83ee4..1480b3182e 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -80,7 +80,7 @@ namespace MWMechanics DynamicStat magicka = creatureStats.getMagicka(); magicka.setBase (static_cast (intelligence + magickaFactor * intelligence)); creatureStats.setMagicka (magicka); - + DynamicStat fatigue = creatureStats.getFatigue(); fatigue.setBase (strength+willpower+agility+endurance); creatureStats.setFatigue (fatigue); @@ -95,7 +95,7 @@ namespace MWMechanics bool stunted = stats.getMagicEffects ().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0; int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); - + DynamicStat health = stats.getHealth(); health.setCurrent (health.getCurrent() + 0.1 * endurance); stats.setHealth (health); @@ -114,15 +114,15 @@ namespace MWMechanics float x = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); x *= fEndFatigueMult * endurance; - + DynamicStat fatigue = stats.getFatigue(); fatigue.setCurrent (fatigue.getCurrent() + 3600 * x); stats.setFatigue (fatigue); - + if (!stunted) { float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat (); - + DynamicStat magicka = stats.getMagicka(); magicka.setCurrent (magicka.getCurrent() + fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified()); @@ -148,22 +148,25 @@ namespace MWMechanics // dynamic stats MagicEffects effects = creatureStats.getMagicEffects(); - + for (int i=0; i<3; ++i) { DynamicStat stat = creatureStats.getDynamic (i); - + stat.setModifier ( effects.get (EffectKey(80+i)).mMagnitude - effects.get (EffectKey(18+i)).mMagnitude); - + creatureStats.setDynamic (i, stat); - } + } } Actors::Actors() : mDuration (0) {} void Actors::addActor (const MWWorld::Ptr& ptr) { + // erase previous death events since we are currently only tracking them while in an active cell + MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); if(!MWWorld::Class::get(ptr).getCreatureStats(ptr).isDead()) mActors.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); @@ -277,7 +280,7 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) calculateRestoration(iter->first, 3600); } - + int Actors::countDeaths (const std::string& id) const { std::map::const_iterator iter = mDeathCount.find(id); From e4ed5b836e10e663e2accb78c4d6176fa76e1876 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 11:04:47 +0100 Subject: [PATCH 0080/1537] added ondeath script function --- apps/openmw/mwscript/docs/vmformat.txt | 3 ++- apps/openmw/mwscript/statsextensions.cpp | 27 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 283f149de2..0f07b4d2e8 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -315,5 +315,6 @@ op 0x20001f8: Drop op 0x20001f9: Drop, explicit reference op 0x20001fa: DropSoulGem op 0x20001fb: DropSoulGem, explicit reference +op 0x20001fc: OnDeath -opcodes 0x20001fa-0x3ffffff unused +opcodes 0x20001fd-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 530d44c9dd..c5fc9436be 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1025,6 +1025,27 @@ namespace MWScript } }; + class OpOnDeath : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWScript::InterpreterContext& context + = static_cast (runtime.getContext()); + + MWWorld::Ptr ptr = context.getReference(); + + Interpreter::Type_Integer value = + MWWorld::Class::get (ptr).getCreatureStats (ptr).hasDied(); + + if (value) + MWWorld::Class::get (ptr).getCreatureStats (ptr).clearHasDied(); + + runtime.push (value); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -1114,6 +1135,8 @@ namespace MWScript const int opcodeLowerRank = 0x20001ea; const int opcodeLowerRankExplicit = 0x20001eb; + const int opcodeOnDeath = 0x20001fc; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -1227,6 +1250,8 @@ namespace MWScript extensions.registerInstruction ("pcclearexpelled", "/S", opcodePcClearExpelled, opcodePcClearExpelledExplicit); extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit); extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); + + extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -1341,6 +1366,8 @@ namespace MWScript interpreter.installSegment5 (opcodeRaiseRankExplicit, new OpRaiseRank); interpreter.installSegment5 (opcodeLowerRank, new OpLowerRank); interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); + + interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); } } } From 4711135e7f6ced616e0e6166337771cb6f6da9fc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 18 Mar 2013 12:05:54 +0100 Subject: [PATCH 0081/1537] workaround for faulty endif in Morrowind scripts --- components/compiler/scriptparser.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/components/compiler/scriptparser.cpp b/components/compiler/scriptparser.cpp index ac0ee63f1c..5b3d244b0d 100644 --- a/components/compiler/scriptparser.cpp +++ b/components/compiler/scriptparser.cpp @@ -2,6 +2,8 @@ #include "scriptparser.hpp" #include "scanner.hpp" +#include "skipparser.hpp" +#include "errorhandler.hpp" namespace Compiler { @@ -41,6 +43,17 @@ namespace Compiler return true; } + /// \todo add an option to disable this nonsense + if (keyword==Scanner::K_endif) + { + // surplus endif + getErrorHandler().warning ("endif without matching if/elseif", loc); + + SkipParser skip (getErrorHandler(), getContext()); + scanner.scan (skip); + return true; + } + if (keyword==Scanner::K_end && mEnd) { return false; From a07c910d0bca8318c03d147f5330c953155b4b7f Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 18 Mar 2013 21:33:12 +0100 Subject: [PATCH 0082/1537] Feature #535: Console object selection improvements --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/tooltips.cpp | 31 +++++++++++++++++++++++--- apps/openmw/mwgui/windowmanagerimp.cpp | 7 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 ++++- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 93cc8e44a2..cd28bb47e7 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -91,6 +91,8 @@ namespace MWBase virtual bool isGuiMode() const = 0; + virtual bool isConsoleMode() const = 0; + virtual void toggleVisible (MWGui::GuiWindow wnd) = 0; /// Disallow all inventory mode windows diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 8eb0336a79..6a2550e4f5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -81,8 +81,33 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) - || (mWindowManager->getMode() == GM_Container) + if (mWindowManager->getWorldMouseOver() && (mWindowManager->getMode() == GM_Console)) + { + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); + if (!object.isEmpty()) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=object.getCellRef().mRefID; + info.icon=""; + IntSize tooltipSize = createToolTip(info); + IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); + + 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); + } + } + + if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Container) || (mWindowManager->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -90,7 +115,7 @@ void ToolTips::onFrame(float frameDuration) if (mFocusObject.isEmpty ()) return; - MyGUI::IntSize tooltipSize = getToolTipViaPtr(true); + IntSize tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 3da739e260..b7d6ed1c9b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1020,6 +1020,13 @@ bool WindowManager::isGuiMode() const return !mGuiModes.empty(); } +bool WindowManager::isConsoleMode() const +{ + if (mGuiModes.back()==GM_Console) + return true; + return false; +} + MWGui::GuiMode WindowManager::getMode() const { if (mGuiModes.empty()) diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 122b10cc39..a7baf5207e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -102,6 +102,8 @@ namespace MWGui virtual bool isGuiMode() const; + virtual bool isConsoleMode() const; + virtual void toggleVisible(GuiWindow wnd); // Disallow all inventory mode windows diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0a874513c3..73bb10a48f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -671,11 +671,12 @@ namespace MWWorld return MWWorld::Ptr (); MWWorld::Ptr object = searchPtrViaHandle (result.second); - float ActivationDistance; if (object.getTypeName ().find("NPC") != std::string::npos) ActivationDistance = getNpcActivationDistance (); + else if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + ActivationDistance = getObjectActivationDistance ()*50; else ActivationDistance = getObjectActivationDistance (); @@ -1010,6 +1011,8 @@ namespace MWWorld float x, y; MWBase::Environment::get().getWindowManager()->getMousePosition(x, y); results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()); + if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + results = mPhysics->getFacedHandles(x, y, getMaxActivationDistance ()*50); } else { From f5bf7254a8febba57f747d8a1773e32ad36b803a Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 18 Mar 2013 23:46:17 +0100 Subject: [PATCH 0083/1537] Minor console selection improvements --- apps/openmw/mwgui/tooltips.cpp | 23 +++++++++++++++-------- apps/openmw/mwworld/worldimp.cpp | 6 +++--- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 6a2550e4f5..1455be8b0f 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -83,15 +83,22 @@ void ToolTips::onFrame(float frameDuration) if (mWindowManager->getWorldMouseOver() && (mWindowManager->getMode() == GM_Console)) { - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); - if (!object.isEmpty()) + MWWorld::Ptr objectptr = MWBase::Environment::get().getWorld()->getFacedObject(); + if (!objectptr.isEmpty()) { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=object.getCellRef().mRefID; - info.icon=""; - IntSize tooltipSize = createToolTip(info); + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + IntSize tooltipSize; + if (!objectclass.hasToolTip(mFocusObject)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=objectptr.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); if ((tooltipPosition.left + tooltipSize.width) > viewSize.width) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 73bb10a48f..1b5dc3bd35 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -673,10 +673,10 @@ namespace MWWorld MWWorld::Ptr object = searchPtrViaHandle (result.second); float ActivationDistance; - if (object.getTypeName ().find("NPC") != std::string::npos) - ActivationDistance = getNpcActivationDistance (); - else if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) + if (MWBase::Environment::get().getWindowManager()->isConsoleMode()) ActivationDistance = getObjectActivationDistance ()*50; + else if (object.getTypeName ().find("NPC") != std::string::npos) + ActivationDistance = getNpcActivationDistance (); else ActivationDistance = getObjectActivationDistance (); From dd11ae04ee9501e270b2ead3c943f9e08ebeb927 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 19 Mar 2013 17:25:41 +0100 Subject: [PATCH 0084/1537] Console code cleaned --- apps/openmw/mwgui/tooltips.cpp | 50 ++++++++++------------------------ 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 1455be8b0f..a8f228ff8b 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -81,48 +81,28 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && (mWindowManager->getMode() == GM_Console)) - { - MWWorld::Ptr objectptr = MWBase::Environment::get().getWorld()->getFacedObject(); - if (!objectptr.isEmpty()) - { - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); - IntSize tooltipSize; - if (!objectclass.hasToolTip(mFocusObject)) - { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=objectptr.getCellRef().mRefID; - info.icon=""; - tooltipSize = createToolTip(info); - } - else - tooltipSize = getToolTipViaPtr(true); - IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); - - 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); - } - } - - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Container) + if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) + || (mWindowManager->getMode() == GM_Container) || (mWindowManager->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); if (mFocusObject.isEmpty ()) return; - IntSize tooltipSize = getToolTipViaPtr(true); + IntSize tooltipSize; + if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=mFocusObject.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); From 3bd545ed8e6861264ef17961d4b9b98726fc3793 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 19 Mar 2013 21:55:37 +0100 Subject: [PATCH 0085/1537] In-console nonexistent class fix --- apps/openmw/mwgui/tooltips.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index a8f228ff8b..af3e146bba 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -86,11 +86,12 @@ void ToolTips::onFrame(float frameDuration) || (mWindowManager->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); if (mFocusObject.isEmpty ()) return; + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + IntSize tooltipSize; if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) { From 2509b34ace037a65d0ecc5b205f69bc1c7c9b8f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 02:48:10 +0100 Subject: [PATCH 0086/1537] Enabled bloodmoon weather --- apps/openmw/mwworld/weather.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 35b5b59cf2..3e85253123 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -317,19 +317,19 @@ void WeatherManager::update(float duration) float thunder = region->mData.mThunder/255.f; float ash = region->mData.mAsh/255.f; float blight = region->mData.mBlight/255.f; - //float snow = region->mData.a/255.f; - //float blizzard = region->mData.b/255.f; + float snow = region->mData.mA/255.f; + float blizzard = region->mData.mB/255.f; // re-scale to 100 percent - const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; + const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight+snow+blizzard; 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) + 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"; From b9c3a4816d118d490eec9e2a397d013b93accc2e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 03:30:15 +0100 Subject: [PATCH 0087/1537] Fix dialogue topics still being accessible in the history pane when they shouldn't be --- apps/openmw/mwgui/dialogue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index c500cd1747..0bbf7c7af4 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -175,6 +175,9 @@ void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) if (!mEnabled && color == "#572D21") MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + if (!mEnabled) + return; + if(color != "#B29154") { MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); From 4cbb20230617d8e3ca98cfd603d37eeafcf99532 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 03:31:01 +0100 Subject: [PATCH 0088/1537] Several tooltip fixes --- apps/openmw/mwgui/map_window.cpp | 12 +++++------ files/mygui/openmw_tooltips.layout | 32 ++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index 52b108f850..d0f3f921e5 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -190,8 +190,8 @@ void LocalMapBase::setActiveCell(const int x, const int y, bool interior) widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", marker.name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); markerWidget->setUserString("IsMarker", "true"); markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); @@ -323,16 +323,16 @@ void MapWindow::addVisitedLocation(const std::string& name, int x, int y) widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); markerWidget->setImageResource("DoorMarker"); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); ++_counter; markerWidget = mEventBoxGlobal->createWidget("", widgetCoord, MyGUI::Align::Default); markerWidget->setNeedMouseFocus (true); markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTip"); - markerWidget->setUserString("Caption_Text", name); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); } void MapWindow::cellExplored(int x, int y) diff --git a/files/mygui/openmw_tooltips.layout b/files/mygui/openmw_tooltips.layout index f554e2b0d5..7291f2ca21 100644 --- a/files/mygui/openmw_tooltips.layout +++ b/files/mygui/openmw_tooltips.layout @@ -7,7 +7,17 @@ - + + + + + + + + + + + @@ -106,12 +116,14 @@ - + + - + + @@ -147,10 +159,12 @@ + - + + @@ -200,17 +214,23 @@ + + - + + - + + + + From 11aed7474eba3aeca00cebf77ccece3c126cfa74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 20 Mar 2013 18:34:54 +0100 Subject: [PATCH 0089/1537] Shadow cast on water --- files/materials/water.mat | 19 +++++++++ files/materials/water.shader | 76 +++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/files/materials/water.mat b/files/materials/water.mat index 0ec71d2df7..1e5f8c8e04 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -54,5 +54,24 @@ material Water scale 0.1 0.1 alpha_op_ex source1 src_manual src_current 0.7 } + + texture_unit shadowMap0 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap1 + { + content_type shadow + tex_address_mode clamp + filtering none + } + texture_unit shadowMap2 + { + content_type shadow + tex_address_mode clamp + filtering none + } } } diff --git a/files/materials/water.shader b/files/materials/water.shader index 793cdc95e3..a6d0a47e6e 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -50,6 +50,13 @@ // Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) +#define SHADOWS_PSSM @shGlobalSettingBool(shadows_pssm) +#define SHADOWS @shGlobalSettingBool(shadows) + +#if SHADOWS || SHADOWS_PSSM + #include "shadows.h" +#endif + #define RIPPLES 1 #define REFRACTION @shGlobalSettingBool(refraction) @@ -64,6 +71,23 @@ shOutput(float4, position) shOutput(float, depthPassthrough) + +#if SHADOWS + shOutput(float4, lightSpacePos0) + shUniform(float4x4, texViewProjMatrix0) @shAutoConstant(texViewProjMatrix0, texture_viewproj_matrix) +#endif + +#if SHADOWS_PSSM + @shForeach(3) + shOutput(float4, lightSpacePos@shIterator) + shUniform(float4x4, texViewProjMatrix@shIterator) @shAutoConstant(texViewProjMatrix@shIterator, texture_viewproj_matrix, @shIterator) + @shEndForeach +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) +#endif + SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); @@ -88,6 +112,17 @@ position = shInputPosition; depthPassthrough = shOutputPosition.z; + + +#if SHADOWS + lightSpacePos0 = shMatrixMult(texViewProjMatrix0, shMatrixMult(worldMatrix, shInputPosition)); +#endif +#if SHADOWS_PSSM + float4 wPos = shMatrixMult(worldMatrix, shInputPosition); + @shForeach(3) + lightSpacePos@shIterator = shMatrixMult(texViewProjMatrix@shIterator, wPos); + @shEndForeach +#endif } #else @@ -186,10 +221,47 @@ shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position_object_space) + + +#if SHADOWS + shInput(float4, lightSpacePos0) + shSampler2D(shadowMap0) + shUniform(float2, invShadowmapSize0) @shAutoConstant(invShadowmapSize0, inverse_texture_size, 1) +#endif +#if SHADOWS_PSSM + @shForeach(3) + shInput(float4, lightSpacePos@shIterator) + shSampler2D(shadowMap@shIterator) + shUniform(float2, invShadowmapSize@shIterator) @shAutoConstant(invShadowmapSize@shIterator, inverse_texture_size, @shIterator(1)) + @shEndForeach + shUniform(float3, pssmSplitPoints) @shSharedParameter(pssmSplitPoints) +#endif + +#if SHADOWS || SHADOWS_PSSM + shUniform(float4, shadowFar_fadeStart) @shSharedParameter(shadowFar_fadeStart) +#endif SH_START_PROGRAM { +#if SHADOWS + float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); +#endif +#if SHADOWS_PSSM + float shadow = pssmDepthShadow (lightSpacePos0, invShadowmapSize0, shadowMap0, lightSpacePos1, invShadowmapSize1, shadowMap1, lightSpacePos2, invShadowmapSize2, shadowMap2, depthPassthrough, pssmSplitPoints); +#endif + +#if SHADOWS || SHADOWS_PSSM + float fadeRange = shadowFar_fadeStart.x - shadowFar_fadeStart.y; + float fade = 1-((depthPassthrough - shadowFar_fadeStart.y) / fadeRange); + shadow = (depthPassthrough > shadowFar_fadeStart.x) ? 1.0 : ((depthPassthrough > shadowFar_fadeStart.y) ? 1.0-((1.0-shadow)*fade) : shadow); +#endif + +#if !SHADOWS && !SHADOWS_PSSM + float shadow = 1.0; +#endif + + float2 screenCoords = screenCoordsPassthrough.xy / screenCoordsPassthrough.z; screenCoords.y = (1-shSaturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y; @@ -244,7 +316,7 @@ float3 llR = reflect(lVec, pNormal); float s = shSaturate(dot(lR, vVec)*2.0-1.2); - float lightScatter = shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); + float lightScatter = shadow * shSaturate(dot(-lVec,lNormal)*0.7+0.3) * s * SCATTER_AMOUNT * waterSunFade_sunHeight.x * shSaturate(1.0-exp(-waterSunFade_sunHeight.y)); float3 scatterColour = shLerp(float3(SCATTER_COLOUR)*float3(1.0,0.4,0.0), SCATTER_COLOUR, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); // fresnel @@ -267,7 +339,7 @@ #endif // specular - float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS); + float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; #if REFRACTION shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz; From ad3478c8f276dc6c9546ef9fb79fbd322e565bef Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 02:02:09 +0100 Subject: [PATCH 0090/1537] Fix inverted dialogue functions (NotClass etc.) The comparison present is useless for these functions. --- apps/openmw/mwdialogue/filter.cpp | 11 +++++++++-- apps/openmw/mwdialogue/selectwrapper.cpp | 25 +++++++++++++----------- apps/openmw/mwdialogue/selectwrapper.hpp | 5 ++--- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 7b5f354a23..8e8ac4db5e 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -136,8 +136,12 @@ bool MWDialogue::Filter::testDisposition (const ESM::DialInfo& info, bool invert bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const { - if (select.isNpcOnly() && mActor.getTypeName()!=typeid (ESM::NPC).name()) - return select.isInverted(); + if (select.isNpcOnly() && (mActor.getTypeName() != typeid (ESM::NPC).name())) + // If the actor is a creature, we do not test the conditions applicable + // only to NPCs. Such conditions can never be satisfied, apart + // inverted ones (NotClass, NotRace, NotFaction return true + // because creatures are not of any race, class or faction). + return select.getType() == SelectWrapper::Type_Inverted; switch (select.getType()) { @@ -145,6 +149,9 @@ bool MWDialogue::Filter::testSelectStruct (const SelectWrapper& select) const case SelectWrapper::Type_Integer: return select.selectCompare (getSelectStructInteger (select)); case SelectWrapper::Type_Numeric: return testSelectStructNumeric (select); case SelectWrapper::Type_Boolean: return select.selectCompare (getSelectStructBoolean (select)); + + // We must not do the comparison for inverted functions (eg. Function_NotClass) + case SelectWrapper::Type_Inverted: return getSelectStructBoolean (select); } return true; diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 77930ae423..81a4153601 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -219,7 +219,6 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function booleanFunctions[] = { Function_False, - Function_NotId, Function_NotFaction, Function_NotClass, Function_NotRace, Function_NotCell, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcCommonDisease, Function_PcBlightDisease, Function_PcCorprus, Function_PcExpelled, @@ -231,6 +230,13 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const Function_None // end marker }; + static const Function invertedBooleanFunctions[] = + { + Function_NotId, Function_NotFaction, Function_NotClass, + Function_NotRace, Function_NotCell, + Function_None // end marker + }; + Function function = getFunction(); for (int i=0; integerFunctions[i]!=Function_None; ++i) @@ -245,16 +251,13 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const if (booleanFunctions[i]==function) return Type_Boolean; + for (int i=0; invertedBooleanFunctions[i]!=Function_None; ++i) + if (invertedBooleanFunctions[i]==function) + return Type_Inverted; + return Type_None; } -bool MWDialogue::SelectWrapper::isInverted() const -{ - char type = mSelect.mSelectRule[1]; - - return type=='7' || type=='8' || type=='9' || type=='A' || type=='B' || type=='C'; -} - bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = @@ -283,17 +286,17 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const bool MWDialogue::SelectWrapper::selectCompare (int value) const { - return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR + return selectCompareImp (mSelect, value); } bool MWDialogue::SelectWrapper::selectCompare (float value) const { - return selectCompareImp (mSelect, value)!=isInverted(); // logic XOR + return selectCompareImp (mSelect, value); } bool MWDialogue::SelectWrapper::selectCompare (bool value) const { - return selectCompareImp (mSelect, static_cast (value))!=isInverted(); // logic XOR + return selectCompareImp (mSelect, static_cast (value)); } std::string MWDialogue::SelectWrapper::getName() const diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index c27339afa0..0548c60cbb 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -50,7 +50,8 @@ namespace MWDialogue Type_None, Type_Integer, Type_Numeric, - Type_Boolean + Type_Boolean, + Type_Inverted }; private: @@ -67,8 +68,6 @@ namespace MWDialogue Type getType() const; - bool isInverted() const; - bool isNpcOnly() const; ///< \attention Do not call any of the select functions for this select struct! From f25b56ac8867b32584295baa1112ffadf6e33187 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 02:06:06 +0100 Subject: [PATCH 0091/1537] Add dialogue function: NotLocal --- apps/openmw/mwdialogue/filter.cpp | 24 ++++++++++++++++++++++++ apps/openmw/mwdialogue/selectwrapper.cpp | 4 ++-- apps/openmw/mwdialogue/selectwrapper.hpp | 1 + 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 8e8ac4db5e..c2d0515dd7 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -440,6 +440,30 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co return Misc::StringUtils::lowerCase (mActor.getCell()->mCell->mName)!=select.getName(); + case SelectWrapper::Function_NotLocal: + { + std::string scriptName = MWWorld::Class::get (mActor).getScript (mActor); + + if (scriptName.empty()) + // This actor has no attached script, so there is no local variable + return true; + + const ESM::Script *script = + MWBase::Environment::get().getWorld()->getStore().get().find (scriptName); + + std::string name = select.getName(); + + int i = 0; + for (; i < script->mVarNames.size(); ++i) + if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) + break; + + if (i >= script->mVarNames.size()) + return true; // script does not have a variable of this name + + return false; + } + case SelectWrapper::Function_SameGender: return (player.get()->mBase->mFlags & ESM::NPC::Female)== diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 81a4153601..d48a06323e 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -117,7 +117,7 @@ MWDialogue::SelectWrapper::Function MWDialogue::SelectWrapper::getFunction() con case '9': return Function_NotClass; case 'A': return Function_NotRace; case 'B': return Function_NotCell; - case 'C': return Function_Local; + case 'C': return Function_NotLocal; } return Function_None; @@ -233,7 +233,7 @@ MWDialogue::SelectWrapper::Type MWDialogue::SelectWrapper::getType() const static const Function invertedBooleanFunctions[] = { Function_NotId, Function_NotFaction, Function_NotClass, - Function_NotRace, Function_NotCell, + Function_NotRace, Function_NotCell, Function_NotLocal, Function_None // end marker }; diff --git a/apps/openmw/mwdialogue/selectwrapper.hpp b/apps/openmw/mwdialogue/selectwrapper.hpp index 0548c60cbb..f4bc898a4b 100644 --- a/apps/openmw/mwdialogue/selectwrapper.hpp +++ b/apps/openmw/mwdialogue/selectwrapper.hpp @@ -22,6 +22,7 @@ namespace MWDialogue Function_NotClass, Function_NotRace, Function_NotCell, + Function_NotLocal, Function_Local, Function_Global, Function_SameGender, Function_SameRace, Function_SameFaction, From 8de93db488dba3f9543c9a73a2824613d89e8f15 Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 02:06:36 +0100 Subject: [PATCH 0092/1537] Coding style consistence --- apps/openmw/mwdialogue/selectwrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index d48a06323e..64bd1d2449 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -262,7 +262,7 @@ bool MWDialogue::SelectWrapper::isNpcOnly() const { static const Function functions[] = { - Function_NotFaction, SelectWrapper::Function_NotClass, SelectWrapper::Function_NotRace, + Function_NotFaction, Function_NotClass, Function_NotRace, Function_SameGender, Function_SameRace, Function_SameFaction, Function_PcSkill, Function_PcExpelled, From 6783ff67483b5a227975f1ce76d35f3713e89caa Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sun, 17 Mar 2013 03:17:05 +0100 Subject: [PATCH 0093/1537] Workaround to have dialogues until actor detection is implemented for NPCs --- apps/openmw/mwworld/class.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 985d35d45e..108efddd81 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -169,7 +169,7 @@ namespace MWWorld bool Class::hasDetected (const MWWorld::Ptr& ptr, const MWWorld::Ptr& ptr2) const { - return false; + return true; } float Class::getArmorRating (const MWWorld::Ptr& ptr) const From cd84b68e4b58572cf0e896c83f4968ee41c65e55 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 20 Mar 2013 20:55:48 +0100 Subject: [PATCH 0094/1537] silencing some warnings --- apps/openmw/mwdialogue/filter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index c2d0515dd7..cd9908d3df 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -454,11 +454,11 @@ bool MWDialogue::Filter::getSelectStructBoolean (const SelectWrapper& select) co std::string name = select.getName(); int i = 0; - for (; i < script->mVarNames.size(); ++i) + for (; i < static_cast (script->mVarNames.size()); ++i) if (Misc::StringUtils::lowerCase(script->mVarNames[i]) == name) break; - if (i >= script->mVarNames.size()) + if (i >= static_cast (script->mVarNames.size())) return true; // script does not have a variable of this name return false; From d05508db52c52f5a3973c387fe5e21864859e70d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 10:07:25 +0100 Subject: [PATCH 0095/1537] switching editor id tables from QAbstractTableModel to QAbstractItemModel (in preparation for record types like containers) --- apps/opencs/model/world/commands.cpp | 2 +- apps/opencs/model/world/data.cpp | 10 +++++----- apps/opencs/model/world/data.hpp | 10 +++++----- apps/opencs/model/world/idtable.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/idtable.hpp | 9 +++++++-- apps/opencs/view/world/dialoguesubview.cpp | 4 ++-- 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index e22ecf9921..1f8660bdde 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -1,7 +1,7 @@ #include "commands.hpp" -#include +#include #include "idtableproxymodel.hpp" #include "idtable.hpp" diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index bbd8667b34..06e638b07f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -3,7 +3,7 @@ #include -#include +#include #include #include @@ -12,7 +12,7 @@ #include "idtable.hpp" #include "columns.hpp" -void CSMWorld::Data::addModel (QAbstractTableModel *model, UniversalId::Type type1, +void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2) { mModels.push_back (model); @@ -42,7 +42,7 @@ CSMWorld::Data::Data() CSMWorld::Data::~Data() { - for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) + for (std::vector::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) delete *iter; } @@ -66,9 +66,9 @@ CSMWorld::IdCollection& CSMWorld::Data::getGmsts() return mGmsts; } -QAbstractTableModel *CSMWorld::Data::getTableModel (const UniversalId& id) +QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { - std::map::iterator iter = mModelIndex.find (id.getType()); + std::map::iterator iter = mModelIndex.find (id.getType()); if (iter==mModelIndex.end()) throw std::logic_error ("No table model available for " + id.toString()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 3745346511..e42d5c1026 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -12,7 +12,7 @@ #include "idcollection.hpp" #include "universalid.hpp" -class QAbstractTableModel; +class QAbstractItemModel; namespace CSMWorld { @@ -20,14 +20,14 @@ namespace CSMWorld { IdCollection mGlobals; IdCollection mGmsts; - std::vector mModels; - std::map mModelIndex; + std::vector mModels; + std::map mModelIndex; // not implemented Data (const Data&); Data& operator= (const Data&); - void addModel (QAbstractTableModel *model, UniversalId::Type type1, + void addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2 = UniversalId::Type_None); public: @@ -44,7 +44,7 @@ namespace CSMWorld IdCollection& getGmsts(); - QAbstractTableModel *getTableModel (const UniversalId& id); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// /// \note The returned table may either be the model for the ID itself or the model that diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index afed6b6eda..79e33584b2 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -96,6 +96,25 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren return true; } +QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const +{ + if (parent.isValid()) + return QModelIndex(); + + if (row<0 || row>=mIdCollection->getSize()) + return QModelIndex(); + + if (column<0 || column>=mIdCollection->getColumns()) + return QModelIndex(); + + return createIndex (row, column); +} + +QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const +{ + return QModelIndex(); +} + void CSMWorld::IdTable::addRecord (const std::string& id) { int index = mIdCollection->getSize(); diff --git a/apps/opencs/model/world/idtable.hpp b/apps/opencs/model/world/idtable.hpp index deaebaa38a..80476c5243 100644 --- a/apps/opencs/model/world/idtable.hpp +++ b/apps/opencs/model/world/idtable.hpp @@ -1,14 +1,14 @@ #ifndef CSM_WOLRD_IDTABLE_H #define CSM_WOLRD_IDTABLE_H -#include +#include namespace CSMWorld { class IdCollectionBase; class RecordBase; - class IdTable : public QAbstractTableModel + class IdTable : public QAbstractItemModel { Q_OBJECT @@ -39,6 +39,11 @@ namespace CSMWorld virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); + virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex()) + const; + + virtual QModelIndex parent (const QModelIndex& index) const; + void addRecord (const std::string& id); QModelIndex getModelIndex (const std::string& id, int column) const; diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index e16de99eff..cedb20de92 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include @@ -24,7 +24,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM widget->setLayout (layout); - QAbstractTableModel *model = document.getData().getTableModel (id); + QAbstractItemModel *model = document.getData().getTableModel (id); int columns = model->columnCount(); From 5346508471d6339bc251679fb284b56aaed5ca29 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 10:16:32 +0100 Subject: [PATCH 0096/1537] added kate junk to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 776e2b6591..27d3a13de3 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ data CMakeLists.txt.user *.swp *.swo +*.kate-swp From ebb1dab8e12a593e8862ff75759c32597bac4316 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 10:19:07 +0100 Subject: [PATCH 0097/1537] removed debugging leftovers --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 7a88335c89..c6b8bbc73d 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2,7 +2,7 @@ #include "document.hpp" #include -#include + void CSMDoc::Document::load (const std::vector::const_iterator& begin, const std::vector::const_iterator& end, bool lastAsModified) { From cafbabde457172584c3e776b587a52975daec96a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 12:13:32 +0100 Subject: [PATCH 0098/1537] fixed broken loading of single files into the editor --- apps/opencs/model/doc/document.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index c6b8bbc73d..47cf1f6642 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -214,7 +214,7 @@ CSMDoc::Document::Document (const std::vector& files, b if (new_ && files.size()==1) createBase(); - else if (files.size()>1) + else { std::vector::const_iterator end = files.end(); From 9464f45d57aacbb16455ff58755f4af46e8feb8b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 12:47:22 +0100 Subject: [PATCH 0099/1537] fixed an encoding problem. I hate you QString. I hate you so much --- apps/opencs/model/world/columns.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 018825831b..1492e96b7d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -35,7 +35,7 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mId.c_str(); + return QString::fromUtf8 (record.get().mId.c_str()); } virtual bool isEditable() const @@ -127,17 +127,17 @@ namespace CSMWorld { case ESM::VT_String: - return record.get().mValue.getString().c_str(); break; + return QString::fromUtf8 (record.get().mValue.getString().c_str()); case ESM::VT_Int: case ESM::VT_Short: case ESM::VT_Long: - return record.get().mValue.getInteger(); break; + return record.get().mValue.getInteger(); case ESM::VT_Float: - return record.get().mValue.getFloat(); break; + return record.get().mValue.getFloat(); default: return QVariant(); } From 1d1471b81c9b35f9faabdbbf575151491bf2701c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 12:57:10 +0100 Subject: [PATCH 0100/1537] fixed a bug in ESM::Variant::write (was affecting string values) --- components/esm/variant.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index d25072e548..a7859d1283 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -186,7 +186,7 @@ void ESM::Variant::write (std::ostream& stream) const case VT_String: - stream << "variant string: \"" << mData->getString() << "\2"; + stream << "variant string: \"" << mData->getString() << "\""; break; } } From a955068853b0a4aa83ff31df5dfc492f24fc6b1b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 13:40:55 +0100 Subject: [PATCH 0101/1537] added universal IDs for skills --- apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index c006852bc6..6fce376bea 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -19,6 +19,7 @@ namespace { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -27,6 +28,7 @@ namespace { { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 9ff7d17b18..a412cb6b1e 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -37,8 +37,9 @@ namespace CSMWorld Type_Global, Type_VerificationResults, Type_Gmsts, - Type_Gmst - + Type_Gmst, + Type_Skills, + Type_Skill }; private: From 947ab6635b3b7f038aea4ea233480bb12a2b3778 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 14:29:31 +0100 Subject: [PATCH 0102/1537] removed automatic detection of setting modified to the same value of base with subsequent setting modifiction state to base only (can cause problems with implicitly added records) --- apps/opencs/model/world/record.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index 53bb7ea2ce..e442d0a391 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -81,9 +81,7 @@ namespace CSMWorld throw std::logic_error ("attempt to modify a deleted record"); mModified = modified; - - if (mState!=State_ModifiedOnly) - mState = mBase==mModified ? State_BaseOnly : State_Modified; + mState = State_Modified; } template From 7df0f6aaeed139d02262364ddcb9d777d0717e34 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 14:30:27 +0100 Subject: [PATCH 0103/1537] prepared skill record for use in editor --- components/esm/loadskil.cpp | 25 +++++++++++++++++++++++++ components/esm/loadskil.hpp | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index a4d21c5912..ac9fc27897 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -1,5 +1,7 @@ #include "loadskil.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -98,6 +100,22 @@ void Skill::load(ESMReader &esm) esm.getHNT(mIndex, "INDX"); esm.getHNT(mData, "SKDT", 24); mDescription = esm.getHNOString("DESC"); + + // create an ID from the index and the name (only used in the editor and likely to change in the + // future) + std::ostringstream stream; + + stream << "#"; + + if (mIndex<10) + stream << "0"; + + stream << mIndex; + + if (mIndex>=0 && mIndex Date: Thu, 21 Mar 2013 14:31:32 +0100 Subject: [PATCH 0104/1537] added basic support for skills to editor --- apps/opencs/model/world/data.cpp | 6 +++++- apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 1 + apps/opencs/view/world/subviews.cpp | 3 +++ 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 06e638b07f..6b0a83e74c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -36,8 +36,12 @@ CSMWorld::Data::Data() mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); + mSkills.addColumn (new StringIdColumn); + mSkills.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); + addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); } CSMWorld::Data::~Data() @@ -102,7 +106,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) { case ESM::REC_GLOB: mGlobals.load (reader, base); break; case ESM::REC_GMST: mGmsts.load (reader, base); break; - + case ESM::REC_SKIL: mSkills.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index e42d5c1026..dc9aee0618 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -8,6 +8,7 @@ #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -20,6 +21,7 @@ namespace CSMWorld { IdCollection mGlobals; IdCollection mGmsts; + IdCollection mSkills; std::vector mModels; std::map mModelIndex; diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 995d3ca2e2..267ddf26cc 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -86,6 +86,10 @@ void CSVDoc::View::setupWorldMenu() connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView())); world->addAction (gmsts); + QAction *skills = new QAction (tr ("Skills"), this); + connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); + world->addAction (skills); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -244,6 +248,11 @@ void CSVDoc::View::addGmstsSubView() addSubView (CSMWorld::UniversalId::Type_Gmsts); } +void CSVDoc::View::addSkillsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Skills); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e91a4d4a80..4c5aa40784 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -116,6 +116,7 @@ namespace CSVDoc void addGmstsSubView(); + void addSkillsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 351007ded5..bdff0017b4 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -14,6 +14,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Gmsts, new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Skills, + new CSVDoc::SubViewFactoryWithCreateFlag (false)); + manager.add (CSMWorld::UniversalId::Type_Global, new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file From 8e472cc62495c5a03a61f9661ae34d7a3369df94 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 21 Mar 2013 14:38:06 +0100 Subject: [PATCH 0105/1537] added description column to skill table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ 2 files changed, 27 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1492e96b7d..a84c9ddf64 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -177,6 +177,31 @@ namespace CSMWorld return true; } }; + + template + struct DescriptionColumn : public Column + { + DescriptionColumn() : Column ("Description", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mDescription.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mDescription = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 6b0a83e74c..51ea3e71be 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -39,6 +39,8 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); From 3731ec0541998dab62ee0cf464ddaca4f03237ef Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 21 Mar 2013 19:54:26 +0100 Subject: [PATCH 0106/1537] Praying to God. --- files/opencs/scalable/Palette.svg | 569 ++++++ .../referenceable record type/.directory | 5 + .../referenceable record type/activator.svg | 1088 ++++++++++++ .../referenceable record type/apparatus.svg | 1058 +++++++++++ .../referenceable record type/book.svg | 692 ++++++++ .../referenceable record type/container.svg | 1359 +++++++++++++++ .../light source.svg | 1543 +++++++++++++++++ .../referenceable record type/potion.svg | 1052 +++++++++++ .../referenceable record type/static.svg | 1141 ++++++++++++ .../referenceable record type/weapon.svg | 1175 +++++++++++++ 10 files changed, 9682 insertions(+) create mode 100644 files/opencs/scalable/Palette.svg create mode 100644 files/opencs/scalable/referenceable record type/.directory create mode 100644 files/opencs/scalable/referenceable record type/activator.svg create mode 100644 files/opencs/scalable/referenceable record type/apparatus.svg create mode 100644 files/opencs/scalable/referenceable record type/book.svg create mode 100644 files/opencs/scalable/referenceable record type/container.svg create mode 100644 files/opencs/scalable/referenceable record type/light source.svg create mode 100644 files/opencs/scalable/referenceable record type/potion.svg create mode 100644 files/opencs/scalable/referenceable record type/static.svg create mode 100644 files/opencs/scalable/referenceable record type/weapon.svg diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg new file mode 100644 index 0000000000..f42475330d --- /dev/null +++ b/files/opencs/scalable/Palette.svg @@ -0,0 +1,569 @@ + + + + + + + image/svg+xml + + + + + + Tango Palette + + + Tuomas Kuosmanen + + + + + Garrett Le Sage +Kenneth Wimer +Jakub Steiner + + +http://www.tango-project.org/files/Tango-Palette.svg + + + unify + global + theme + color + palette + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/opencs/scalable/referenceable record type/.directory b/files/opencs/scalable/referenceable record type/.directory new file mode 100644 index 0000000000..e2d80ed58c --- /dev/null +++ b/files/opencs/scalable/referenceable record type/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable record type/activator.svg b/files/opencs/scalable/referenceable record type/activator.svg new file mode 100644 index 0000000000..0c6db59a7d --- /dev/null +++ b/files/opencs/scalable/referenceable record type/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/apparatus.svg b/files/opencs/scalable/referenceable record type/apparatus.svg new file mode 100644 index 0000000000..37cef0e890 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/book.svg b/files/opencs/scalable/referenceable record type/book.svg new file mode 100644 index 0000000000..8c041a9e7a --- /dev/null +++ b/files/opencs/scalable/referenceable record type/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg new file mode 100644 index 0000000000..11ad794384 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -0,0 +1,1359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg new file mode 100644 index 0000000000..8575659f45 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/light source.svg @@ -0,0 +1,1543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg new file mode 100644 index 0000000000..8880065312 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/static.svg b/files/opencs/scalable/referenceable record type/static.svg new file mode 100644 index 0000000000..a6f29370f0 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg new file mode 100644 index 0000000000..1e5aaac41c --- /dev/null +++ b/files/opencs/scalable/referenceable record type/weapon.svg @@ -0,0 +1,1175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + From e46097cd2ed1e1742d63a2d958c8cec6a68645f1 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Thu, 21 Mar 2013 19:54:26 +0100 Subject: [PATCH 0107/1537] Icons. Currently activator, apparatus, book, container (work in progress), light source, potion, static, weapon. --- files/opencs/scalable/Palette.svg | 569 ++++++ .../referenceable record type/.directory | 5 + .../referenceable record type/activator.svg | 1088 ++++++++++++ .../referenceable record type/apparatus.svg | 1058 +++++++++++ .../referenceable record type/book.svg | 692 ++++++++ .../referenceable record type/container.svg | 1359 +++++++++++++++ .../light source.svg | 1543 +++++++++++++++++ .../referenceable record type/potion.svg | 1052 +++++++++++ .../referenceable record type/static.svg | 1141 ++++++++++++ .../referenceable record type/weapon.svg | 1175 +++++++++++++ 10 files changed, 9682 insertions(+) create mode 100644 files/opencs/scalable/Palette.svg create mode 100644 files/opencs/scalable/referenceable record type/.directory create mode 100644 files/opencs/scalable/referenceable record type/activator.svg create mode 100644 files/opencs/scalable/referenceable record type/apparatus.svg create mode 100644 files/opencs/scalable/referenceable record type/book.svg create mode 100644 files/opencs/scalable/referenceable record type/container.svg create mode 100644 files/opencs/scalable/referenceable record type/light source.svg create mode 100644 files/opencs/scalable/referenceable record type/potion.svg create mode 100644 files/opencs/scalable/referenceable record type/static.svg create mode 100644 files/opencs/scalable/referenceable record type/weapon.svg diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg new file mode 100644 index 0000000000..f42475330d --- /dev/null +++ b/files/opencs/scalable/Palette.svg @@ -0,0 +1,569 @@ + + + + + + + image/svg+xml + + + + + + Tango Palette + + + Tuomas Kuosmanen + + + + + Garrett Le Sage +Kenneth Wimer +Jakub Steiner + + +http://www.tango-project.org/files/Tango-Palette.svg + + + unify + global + theme + color + palette + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/opencs/scalable/referenceable record type/.directory b/files/opencs/scalable/referenceable record type/.directory new file mode 100644 index 0000000000..e2d80ed58c --- /dev/null +++ b/files/opencs/scalable/referenceable record type/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable record type/activator.svg b/files/opencs/scalable/referenceable record type/activator.svg new file mode 100644 index 0000000000..0c6db59a7d --- /dev/null +++ b/files/opencs/scalable/referenceable record type/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/apparatus.svg b/files/opencs/scalable/referenceable record type/apparatus.svg new file mode 100644 index 0000000000..37cef0e890 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/book.svg b/files/opencs/scalable/referenceable record type/book.svg new file mode 100644 index 0000000000..8c041a9e7a --- /dev/null +++ b/files/opencs/scalable/referenceable record type/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg new file mode 100644 index 0000000000..11ad794384 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -0,0 +1,1359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg new file mode 100644 index 0000000000..8575659f45 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/light source.svg @@ -0,0 +1,1543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg new file mode 100644 index 0000000000..8880065312 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/static.svg b/files/opencs/scalable/referenceable record type/static.svg new file mode 100644 index 0000000000..a6f29370f0 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg new file mode 100644 index 0000000000..1e5aaac41c --- /dev/null +++ b/files/opencs/scalable/referenceable record type/weapon.svg @@ -0,0 +1,1175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + From 3277ef26dab02aeca1668f0bf1be33cde8edb6e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 21 Mar 2013 21:08:23 +0100 Subject: [PATCH 0108/1537] Fix a crash when dropping objects without a collision shape --- libs/openengine/bullet/physic.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index c4947af1e1..8641996768 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -603,6 +603,14 @@ namespace Physic btTransform trans; trans.setIdentity(); - shape->mCollisionShape->getAabb(trans, min, max); + if (shape->mRaycastingShape) + shape->mRaycastingShape->getAabb(trans, min, max); + else if (shape->mCollisionShape) + shape->mCollisionShape->getAabb(trans, min, max); + else + { + min = btVector3(0,0,0); + max = btVector3(0,0,0); + } } }} From 918cdcffc200da31602d270fac2144d8220ad937 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 05:50:54 +0100 Subject: [PATCH 0109/1537] Split up components/esm/loadlocks --- apps/esmtool/record.cpp | 8 +-- apps/esmtool/record.hpp | 2 +- apps/openmw/mwclass/lockpick.cpp | 36 ++++++------- apps/openmw/mwclass/probe.cpp | 2 +- apps/openmw/mwclass/repair.cpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 2 +- apps/openmw/mwscript/compilercontext.cpp | 2 +- apps/openmw/mwworld/cells.cpp | 2 +- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/containerstore.cpp | 6 +-- apps/openmw/mwworld/containerstore.hpp | 6 +-- apps/openmw/mwworld/esmstore.hpp | 4 +- apps/openmw/mwworld/manualref.hpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/loadlock.cpp | 31 +++++++++++ components/esm/loadlock.hpp | 31 +++++++++++ components/esm/loadlocks.cpp | 65 ------------------------ components/esm/loadlocks.hpp | 56 -------------------- components/esm/loadprob.cpp | 30 +++++++++++ components/esm/loadprob.hpp | 31 +++++++++++ components/esm/loadrepa.cpp | 31 +++++++++++ components/esm/loadrepa.hpp | 31 +++++++++++ components/esm/records.hpp | 4 +- 26 files changed, 228 insertions(+), 166 deletions(-) create mode 100644 components/esm/loadlock.cpp create mode 100644 components/esm/loadlock.hpp delete mode 100644 components/esm/loadlocks.cpp delete mode 100644 components/esm/loadlocks.hpp create mode 100644 components/esm/loadprob.cpp create mode 100644 components/esm/loadprob.hpp create mode 100644 components/esm/loadrepa.cpp create mode 100644 components/esm/loadrepa.hpp diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 38fddd6b92..de3a175106 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -275,7 +275,7 @@ RecordBase::create(ESM::NAME type) } case ESM::REC_LOCK: { - record = new EsmTool::Record; + record = new EsmTool::Record; break; } case ESM::REC_LTEX: @@ -864,14 +864,13 @@ void Record::print() } template<> -void Record::print() +void Record::print() { std::cout << " Name: " << mData.mName << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -886,8 +885,6 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - // BUG? No Type Label? - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; @@ -902,7 +899,6 @@ void Record::print() std::cout << " Icon: " << mData.mIcon << std::endl; if (mData.mScript != "") std::cout << " Script: " << mData.mScript << std::endl; - std::cout << " Type: " << mData.mType << std::endl; std::cout << " Weight: " << mData.mData.mWeight << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Quality: " << mData.mData.mQuality << std::endl; diff --git a/apps/esmtool/record.hpp b/apps/esmtool/record.hpp index c3daa9d0c3..e0dd988a65 100644 --- a/apps/esmtool/record.hpp +++ b/apps/esmtool/record.hpp @@ -104,7 +104,7 @@ namespace EsmTool template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); - template<> void Record::print(); + template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); template<> void Record::print(); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 665644736d..6fa8f55520 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -1,7 +1,7 @@ #include "lockpick.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -41,8 +41,8 @@ namespace MWClass std::string Lockpick::getModel(const MWWorld::Ptr &ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); assert(ref->mBase != NULL); const std::string &model = ref->mBase->mModel; @@ -54,8 +54,8 @@ namespace MWClass std::string Lockpick::getName (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mName; } @@ -75,8 +75,8 @@ namespace MWClass std::string Lockpick::getScript (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mScript; } @@ -92,8 +92,8 @@ namespace MWClass int Lockpick::getValue (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mData.mValue; } @@ -102,7 +102,7 @@ namespace MWClass { boost::shared_ptr instance (new Lockpick); - registerClass (typeid (ESM::Tool).name(), instance); + registerClass (typeid (ESM::Lockpick).name(), instance); } std::string Lockpick::getUpSoundId (const MWWorld::Ptr& ptr) const @@ -117,24 +117,24 @@ namespace MWClass std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return ref->mBase->mIcon; } bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return (ref->mBase->mName != ""); } MWGui::ToolTipInfo Lockpick::getToolTipInfo (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); MWGui::ToolTipInfo info; info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); @@ -171,8 +171,8 @@ namespace MWClass MWWorld::Ptr Lockpick::copyToCellImpl(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell) const { - MWWorld::LiveCellRef *ref = - ptr.get(); + MWWorld::LiveCellRef *ref = + ptr.get(); return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 5b1b55bd31..68d9b49c30 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -1,7 +1,7 @@ #include "probe.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index d6afe93198..8a13aa2078 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -1,7 +1,7 @@ #include "repair.hpp" -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index e476865433..9c1fbae69e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -45,7 +45,7 @@ namespace 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::Lockpick).name() ); mapping.push_back( typeid(ESM::Repair).name() ); mapping.push_back( typeid(ESM::Probe).name() ); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 29966bd08a..578ec3da3e 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -308,7 +308,7 @@ namespace MWGui && (type != typeid(ESM::Ingredient).name()) && (type != typeid(ESM::Light).name()) && (type != typeid(ESM::Miscellaneous).name()) - && (type != typeid(ESM::Tool).name()) + && (type != typeid(ESM::Lockpick).name()) && (type != typeid(ESM::Probe).name()) && (type != typeid(ESM::Repair).name()) && (type != typeid(ESM::Weapon).name()) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 0fd24601a8..f84a0abc88 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -368,7 +368,7 @@ namespace MWGui 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()) + else if (item.getTypeName() == typeid(ESM::Lockpick).name()) return services & ESM::NPC::Picks; else if (item.getTypeName() == typeid(ESM::Probe).name()) return services & ESM::NPC::Probes; diff --git a/apps/openmw/mwscript/compilercontext.cpp b/apps/openmw/mwscript/compilercontext.cpp index 57d93512f4..7e63a33b25 100644 --- a/apps/openmw/mwscript/compilercontext.cpp +++ b/apps/openmw/mwscript/compilercontext.cpp @@ -59,7 +59,7 @@ namespace MWScript store.get().search (name) || store.get().search (name) || store.get().search (name) || - store.get().search (name) || + store.get().search (name) || store.get().search (name) || store.get().search (name) || store.get().search (name) || diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index f95d30df13..5f771be475 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -206,7 +206,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce if (MWWorld::LiveCellRef *ref = cell.mLights.find (name)) ptr = Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) + if (MWWorld::LiveCellRef *ref = cell.mLockpicks.find (name)) ptr = Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = cell.mMiscItems.find (name)) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index c182f196bc..2e6b45bb7e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -112,7 +112,7 @@ namespace MWWorld CellRefList mCreatureLists; CellRefList mItemLists; CellRefList mLights; - CellRefList mLockpicks; + CellRefList mLockpicks; CellRefList mMiscItems; CellRefList mNpcs; CellRefList mProbes; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8a7884e9e0..3dce049f4d 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -171,7 +171,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr case Type_Clothing: clothes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.mList.end()); break; case Type_Ingredient: ingreds.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.mList.end()); break; case Type_Light: lights.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.mList.end()); break; - case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; + case Type_Lockpick: lockpicks.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.mList.end()); break; case Type_Miscellaneous: miscItems.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.mList.end()); break; case Type_Probe: probes.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.mList.end()); break; case Type_Repair: repairs.mList.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.mList.end()); break; @@ -272,7 +272,7 @@ int MWWorld::ContainerStore::getType (const Ptr& ptr) if (ptr.getTypeName()==typeid (ESM::Light).name()) return Type_Light; - if (ptr.getTypeName()==typeid (ESM::Tool).name()) + if (ptr.getTypeName()==typeid (ESM::Lockpick).name()) return Type_Lockpick; if (ptr.getTypeName()==typeid (ESM::Miscellaneous).name()) @@ -321,7 +321,7 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *contain : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} -MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator iterator) : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index e4f75d5478..9d315d27f0 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -44,7 +44,7 @@ namespace MWWorld MWWorld::CellRefList clothes; MWWorld::CellRefList ingreds; MWWorld::CellRefList lights; - MWWorld::CellRefList lockpicks; + MWWorld::CellRefList lockpicks; MWWorld::CellRefList miscItems; MWWorld::CellRefList probes; MWWorld::CellRefList repairs; @@ -127,7 +127,7 @@ namespace MWWorld MWWorld::CellRefList::List::iterator mClothing; MWWorld::CellRefList::List::iterator mIngredient; MWWorld::CellRefList::List::iterator mLight; - MWWorld::CellRefList::List::iterator mLockpick; + MWWorld::CellRefList::List::iterator mLockpick; MWWorld::CellRefList::List::iterator mMiscellaneous; MWWorld::CellRefList::List::iterator mProbe; MWWorld::CellRefList::List::iterator mRepair; @@ -149,7 +149,7 @@ namespace MWWorld ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); - ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); ContainerStoreIterator (ContainerStore *container, MWWorld::CellRefList::List::iterator); diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index b9b95e4f4e..61a106e163 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -32,7 +32,7 @@ namespace MWWorld Store mCreatureLists; Store mItemLists; Store mLights; - Store mLockpicks; + Store mLockpicks; Store mMiscItems; Store mNpcs; Store mNpcChange; @@ -312,7 +312,7 @@ namespace MWWorld } template <> - inline const Store &ESMStore::get() const { + inline const Store &ESMStore::get() const { return mLockpicks; } diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 91b8cf8cd4..466341b953 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -53,7 +53,7 @@ namespace MWWorld !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && - !create (store.get(), name) && + !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && !create (store.get(), name) && diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 1b5dc3bd35..5d6863c029 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -101,7 +101,7 @@ namespace MWWorld return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLights)) return Ptr (ref, &cell); - if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) + if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mLockpicks)) return Ptr (ref, &cell); if (MWWorld::LiveCellRef *ref = searchViaHandle (handle, cell.mMiscItems)) return Ptr (ref, &cell); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index f7b97056cb..88bf764445 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -37,7 +37,7 @@ add_component_dir (file_finder add_component_dir (esm attr defs esmcommon esmreader esmwriter loadacti loadalch loadappa loadarmo loadbody loadbook loadbsgn loadcell loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst - loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc + loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadweap records aipackage effectlist spelllist variant variantimp loadtes3 ) diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp new file mode 100644 index 0000000000..02a36abfe6 --- /dev/null +++ b/components/esm/loadlock.cpp @@ -0,0 +1,31 @@ +#include "loadlock.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Lockpick::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "LKDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Lockpick::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("LKDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + + +} diff --git a/components/esm/loadlock.hpp b/components/esm/loadlock.hpp new file mode 100644 index 0000000000..0bbedf362f --- /dev/null +++ b/components/esm/loadlock.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_LOCK_H +#define OPENMW_ESM_LOCK_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Lockpick +{ + struct Data + { + float mWeight; + int mValue; + + float mQuality; + int mUses; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadlocks.cpp b/components/esm/loadlocks.cpp deleted file mode 100644 index 057da595e7..0000000000 --- a/components/esm/loadlocks.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "loadlocks.hpp" - -#include "esmreader.hpp" -#include "esmwriter.hpp" - -namespace ESM -{ - -void Tool::load(ESMReader &esm) -{ - mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); - - esm.getSubName(); - NAME n = esm.retSubName(); - // The data name varies, RIDT for repair items, LKDT for lock - // picks, PBDT for probes - - esm.getHT(mData, 16); - - if (n == "RIDT") - { - mType = Type_Repair; - // Swap t.data.quality and t.data.uses for repair items (sigh) - float tmp = *((float*) &mData.mUses); - mData.mUses = *((int*) &mData.mQuality); - mData.mQuality = tmp; - } - else if (n == "LKDT") - mType = Type_Pick; - else if (n == "PBDT") - mType = Type_Probe; - - mScript = esm.getHNOString("SCRI"); - mIcon = esm.getHNOString("ITEX"); -} - -void Tool::save(ESMWriter &esm) -{ - esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); - - std::string typeName; - switch(mType) - { - case Type_Repair: typeName = "RIDT"; break; - case Type_Pick: typeName = "LKDT"; break; - case Type_Probe: typeName = "PBDT"; break; - } - - Data write = mData; - if (mType == Type_Repair) - { - float tmp = *((float*) &write.mUses); - write.mUses = *((int*) &write.mQuality); - write.mQuality = tmp; - } - - esm.writeHNT(typeName, write, 16); - esm.writeHNOString("SCRI", mScript); - esm.writeHNOCString("ITEX", mIcon); -} - - -} diff --git a/components/esm/loadlocks.hpp b/components/esm/loadlocks.hpp deleted file mode 100644 index 8e88c548e7..0000000000 --- a/components/esm/loadlocks.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef OPENMW_ESM_LOCKS_H -#define OPENMW_ESM_LOCKS_H - -#include - -namespace ESM -{ - -class ESMReader; -class ESMWriter; - -/* - * This file covers lockpicks (LOCK), probes (PROB) and armor repair - * items (REPA). These have nearly identical data structures. - */ - -struct Tool -{ - enum Type - { - Type_Pick, - Type_Probe, - Type_Repair - }; - - struct Data - { - float mWeight; - int mValue; - - float mQuality; // And when I say nearly identical structure, I - int mUses; // mean perfectly identical except that these two - // variables are swaped for repair items. Don't ask - // me why. - }; // Size = 16 - - Data mData; - Type mType; - std::string mId, mName, mModel, mIcon, mScript; - - void load(ESMReader &esm); - void save(ESMWriter &esm); -}; - -struct Probe: Tool -{ - Probe() { mType = Type_Probe; } -}; - -struct Repair: Tool -{ - Repair() { mType = Type_Repair; } -}; - -} -#endif diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp new file mode 100644 index 0000000000..bbaec1ce2d --- /dev/null +++ b/components/esm/loadprob.cpp @@ -0,0 +1,30 @@ +#include "loadprob.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Probe::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "PBDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Probe::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("PBDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + +} diff --git a/components/esm/loadprob.hpp b/components/esm/loadprob.hpp new file mode 100644 index 0000000000..4a47a86005 --- /dev/null +++ b/components/esm/loadprob.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_PROBE_H +#define OPENMW_ESM_PROBE_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Probe +{ + struct Data + { + float mWeight; + int mValue; + + float mQuality; + int mUses; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp new file mode 100644 index 0000000000..f7eeddf961 --- /dev/null +++ b/components/esm/loadrepa.cpp @@ -0,0 +1,31 @@ +#include "loadrepa.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + +void Repair::load(ESMReader &esm) +{ + mModel = esm.getHNString("MODL"); + mName = esm.getHNString("FNAM"); + + esm.getHNT(mData, "RIDT", 16); + + mScript = esm.getHNOString("SCRI"); + mIcon = esm.getHNOString("ITEX"); +} + +void Repair::save(ESMWriter &esm) +{ + esm.writeHNCString("MODL", mModel); + esm.writeHNCString("FNAM", mName); + + esm.writeHNT("RIDT", mData, 16); + esm.writeHNOString("SCRI", mScript); + esm.writeHNOCString("ITEX", mIcon); +} + + +} diff --git a/components/esm/loadrepa.hpp b/components/esm/loadrepa.hpp new file mode 100644 index 0000000000..60ff5df905 --- /dev/null +++ b/components/esm/loadrepa.hpp @@ -0,0 +1,31 @@ +#ifndef OPENMW_ESM_REPA_H +#define OPENMW_ESM_REPA_H + +#include + +namespace ESM +{ + +class ESMReader; +class ESMWriter; + +struct Repair +{ + struct Data + { + float mWeight; + int mValue; + + int mUses; + float mQuality; + }; // Size = 16 + + Data mData; + std::string mId, mName, mModel, mIcon, mScript; + + void load(ESMReader &esm); + void save(ESMWriter &esm); +}; + +} +#endif diff --git a/components/esm/records.hpp b/components/esm/records.hpp index 0662c797c1..7a0452eb3f 100644 --- a/components/esm/records.hpp +++ b/components/esm/records.hpp @@ -26,7 +26,9 @@ #include "loadland.hpp" #include "loadlevlist.hpp" #include "loadligh.hpp" -#include "loadlocks.hpp" +#include "loadlock.hpp" +#include "loadrepa.hpp" +#include "loadprob.hpp" #include "loadltex.hpp" #include "loadmgef.hpp" #include "loadmisc.hpp" From feaf2b43fbfc7f3c2b3e6b7af859db1dc45b6d4d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 22 Mar 2013 09:44:59 +0100 Subject: [PATCH 0110/1537] disabled and deleted objects where not correctly ignored during adding objects to a cell when it became active --- apps/openmw/mwworld/scene.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 592fb5c80a..339026ca60 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -41,7 +41,7 @@ namespace ++current; - if (it->mData.getCount() || it->mData.isEnabled()) + if (it->mData.getCount() && it->mData.isEnabled()) { MWWorld::Ptr ptr (&*it, &cell); From 8e2f9f5186b6a969c8d73c255bdac7a28cef5ebe Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 12:24:09 +0100 Subject: [PATCH 0111/1537] Fix CellRef to load current weapon/armor health correctly, also show it in the tooltips --- apps/esmtool/esmtool.cpp | 2 +- apps/openmw/mwclass/armor.cpp | 5 +++-- apps/openmw/mwclass/lockpick.cpp | 4 ++-- apps/openmw/mwclass/probe.cpp | 4 ++-- apps/openmw/mwclass/repair.cpp | 4 ++-- apps/openmw/mwclass/weapon.cpp | 7 +++++-- apps/openmw/mwworld/manualref.hpp | 3 +-- components/esm/loadcell.cpp | 17 +++++------------ components/esm/loadcell.hpp | 12 ++++-------- 9 files changed, 25 insertions(+), 33 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 20c01af259..521383f3ff 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -227,7 +227,7 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; - std::cout << " INTV: " << ref.mIntv << " NAM9: " << ref.mIntv << std::endl; + std::cout << " Uses/health: " << ref.mCharge << " NAM9: " << ref.mNam9 << std::endl; } } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index fdf211c28a..513ebf75fc 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -247,8 +247,9 @@ namespace MWClass text += "\n#{sArmorRating}: " + MWGui::ToolTips::toString(ref->mBase->mData.mArmor); - /// \todo store the current armor health somewhere - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight) + " (" + typeText + ")"; text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 6fa8f55520..2015726968 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -142,9 +142,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 68d9b49c30..e4533af655 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -141,9 +141,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 8a13aa2078..f0b6fe88d9 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -131,9 +131,9 @@ namespace MWClass std::string text; - /// \todo store remaining uses somewhere + int remainingUses = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mUses; - text += "\n#{sUses}: " + MWGui::ToolTips::toString(ref->mBase->mData.mUses); + text += "\n#{sUses}: " + MWGui::ToolTips::toString(remainingUses); text += "\n#{sQuality}: " + MWGui::ToolTips::toString(ref->mBase->mData.mQuality); text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 475c08ccbf..e9e42d3fdd 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -334,9 +334,12 @@ namespace MWClass } } - /// \todo store the current weapon health somewhere if (ref->mBase->mData.mType < 11) // thrown weapons and arrows/bolts don't have health, only quantity - text += "\n#{sCondition}: " + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + { + int remainingHealth = (ptr.getCellRef().mCharge != -1) ? ptr.getCellRef().mCharge : ref->mBase->mData.mHealth; + text += "\n#{sCondition}: " + MWGui::ToolTips::toString(remainingHealth) + "/" + + MWGui::ToolTips::toString(ref->mBase->mData.mHealth); + } text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 466341b953..58395d8798 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -68,8 +68,7 @@ namespace MWWorld cellRef.mRefnum = -1; cellRef.mScale = 1; cellRef.mFactIndex = 0; - cellRef.mCharge = 0; - cellRef.mIntv = 0; + cellRef.mCharge = -1; cellRef.mNam9 = 0; cellRef.mTeleport = false; cellRef.mLockLevel = 0; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index da60f76af8..0731a8ff80 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -14,7 +14,7 @@ namespace ESM { -/// Some overloaded copare operators. +/// Some overloaded compare operators. bool operator==(const MovedCellRef& ref, int pRefnum) { return (ref.mRefnum == pRefnum); @@ -43,13 +43,9 @@ void CellRef::save(ESMWriter &esm) esm.writeHNT("INDX", mFactIndex); } - if (mCharge != -1.0) { - esm.writeHNT("XCHG", mCharge); - } + if (mCharge != -1) + esm.writeHNT("INTV", mCharge); - if (mIntv != -1) { - esm.writeHNT("INTV", mIntv); - } if (mNam9 != 0) { esm.writeHNT("NAM9", mNam9); } @@ -285,12 +281,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mFactIndex = -2; esm.getHNOT(ref.mFactIndex, "INDX"); - ref.mCharge = -1.0; - esm.getHNOT(ref.mCharge, "XCHG"); - - ref.mIntv = -1; ref.mNam9 = 0; - esm.getHNOT(ref.mIntv, "INTV"); + ref.mCharge = -1; + esm.getHNOT(ref.mCharge, "INTV"); esm.getHNOT(ref.mNam9, "NAM9"); // Present for doors that teleport you to another cell. diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 7db6dbe77c..97aa86ba0f 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -52,15 +52,11 @@ public: // is -1, which I assume means "any rank". int mFactIndex; - // Depends on context - possibly weapon health, number of uses left - // or weapon magic charge? - float mCharge; + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int mCharge; - // I have no idea, these are present some times, often along with - // owner (ANAM) and sometimes otherwise. They are often (but not - // always) 1. INTV is big for lights (possibly a float?), might have - // something to do with remaining light "charge". - int mIntv, mNam9; + int mNam9; // For doors - true if this door teleports to somewhere else, false // if it should open through animation. From 20774f8f8178ad6a4ee9aea47da09ae0f7b075b4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 14:13:10 +0100 Subject: [PATCH 0112/1537] Added merchant repair feature --- apps/openmw/CMakeLists.txt | 1 + apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 3 + apps/openmw/mwgui/dialogue.cpp | 8 ++ apps/openmw/mwgui/dialogue.hpp | 3 +- apps/openmw/mwgui/merchantrepair.cpp | 132 ++++++++++++++++++ apps/openmw/mwgui/merchantrepair.hpp | 37 +++++ apps/openmw/mwgui/mode.hpp | 2 + apps/openmw/mwgui/spellbuyingwindow.cpp | 11 -- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 - apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 4 + apps/openmw/mwworld/containerstore.cpp | 4 +- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_merchantrepair.layout | 33 +++++ files/mygui/openmw_spell_buying_window.layout | 10 +- 16 files changed, 244 insertions(+), 21 deletions(-) create mode 100644 apps/openmw/mwgui/merchantrepair.cpp create mode 100644 apps/openmw/mwgui/merchantrepair.hpp create mode 100644 files/mygui/openmw_merchantrepair.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0edc18afba..11c6360e57 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,6 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons + merchantrepair ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index cd28bb47e7..0a6de5e14d 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -238,6 +238,7 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; + virtual void startRepair(MWWorld::Ptr actor) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 1628199950..b75c514a29 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -367,6 +367,9 @@ namespace MWDialogue if (services & ESM::NPC::Enchanting) windowServices |= MWGui::DialogueWindow::Service_Enchant; + if (services & ESM::NPC::Repair) + windowServices |= MWGui::DialogueWindow::Service_Repair; + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); win->setServices (windowServices); diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0bbf7c7af4..9a7e51874f 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -280,6 +280,11 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) mWindowManager.pushGuiMode(GM_Training); mWindowManager.startTraining (mPtr); } + else if (topic == gmst.find("sRepair")->getString()) + { + mWindowManager.pushGuiMode(GM_MerchantRepair); + mWindowManager.startRepair (mPtr); + } } } } @@ -327,6 +332,9 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + if (mServices & Service_Repair) + mTopicsList->addItem(gmst.find("sRepair")->getString()); + if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addSeparator(); diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a8e0a6d174..187731fc77 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -81,7 +81,8 @@ namespace MWGui Service_CreateSpells = 0x04, Service_Enchant = 0x08, Service_Training = 0x10, - Service_Travel = 0x20 + Service_Travel = 0x20, + Service_Repair = 0x40 }; protected: diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp new file mode 100644 index 0000000000..0a65326050 --- /dev/null +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -0,0 +1,132 @@ +#include "merchantrepair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "list.hpp" +#include "inventorywindow.hpp" +#include "tradewindow.hpp" + +namespace MWGui +{ + +MerchantRepair::MerchantRepair(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_merchantrepair.layout", parWindowManager) +{ + getWidget(mList, "RepairView"); + getWidget(mOkButton, "OkButton"); + getWidget(mGoldLabel, "PlayerGold"); + + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onOkButtonClick); +} + +void MerchantRepair::startRepair(const MWWorld::Ptr &actor) +{ + mActor = actor; + + while (mList->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mList->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) + { + int maxDurability = MWWorld::Class::get(*iter).getItemMaxHealth(*iter); + int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + if (maxDurability == durability) + continue; + + int basePrice = MWWorld::Class::get(*iter).getValue(*iter); + float fRepairMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fRepairMult")->getFloat(); + + float p = std::max(1, basePrice); + float r = std::max(1, static_cast(maxDurability / p)); + + int x = ((maxDurability - durability) / r); + x = (fRepairMult * x); + + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mActor, x, true); + + + std::string name = MWWorld::Class::get(*iter).getName(*iter) + + " - " + boost::lexical_cast(price) + + MWBase::Environment::get().getWorld()->getStore().get() + .find("sgp")->getString();; + + + MyGUI::Button* button = + mList->createWidget( + (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + 0, + currentY, + 0, + 18, + MyGUI::Align::Default + ); + + currentY += 18; + + button->setEnabled(price<=mWindowManager.getInventoryWindow()->getPlayerGold()); + button->setUserString("Price", boost::lexical_cast(price)); + button->setUserData(*iter); + button->setCaptionWithReplacing(name); + button->setSize(button->getTextSize().width,18); + button->eventMouseWheel += MyGUI::newDelegate(this, &MerchantRepair::onMouseWheel); + button->setUserString("ToolTipType", "ItemPtr"); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MerchantRepair::onRepairButtonClick); + } + } + mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); +} + +void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mList->getViewOffset().top + _rel*0.3 > 0) + mList->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mList->setViewOffset(MyGUI::IntPoint(0, mList->getViewOffset().top + _rel*0.3)); +} + +void MerchantRepair::open() +{ + center(); +} + +void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) +{ + // repair + MWWorld::Ptr item = *sender->getUserData(); + item.getCellRef().mCharge = MWWorld::Class::get(item).getItemMaxHealth(item); + + MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); + + int price = boost::lexical_cast(sender->getUserString("Price")); + mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + + startRepair(mActor); +} + +void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) +{ + mWindowManager.removeGuiMode(GM_MerchantRepair); +} + +} diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp new file mode 100644 index 0000000000..4b7e2b8fbd --- /dev/null +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -0,0 +1,37 @@ +#ifndef OPENMW_MWGUI_MERCHANTREPAIR_H +#define OPENMW_MWGUI_MERCHANTREPAIR_H + +#include "window_base.hpp" +#include "../mwworld/ptr.hpp" + + + +namespace MWGui +{ + +class MerchantRepair : public WindowBase +{ +public: + MerchantRepair(MWBase::WindowManager &parWindowManager); + + virtual void open(); + + void startRepair(const MWWorld::Ptr& actor); + +private: + MyGUI::ScrollView* mList; + MyGUI::Button* mOkButton; + MyGUI::TextBox* mGoldLabel; + + MWWorld::Ptr mActor; + +protected: + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + void onRepairButtonClick(MyGUI::Widget* sender); + void onOkButtonClick(MyGUI::Widget* sender); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 3195372978..4091f47acc 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -16,6 +16,7 @@ namespace MWGui GM_Scroll, // Read scroll GM_Book, // Read book GM_Alchemy, // Make potions + GM_Repair, GM_Dialogue, // NPC interaction GM_Barter, @@ -26,6 +27,7 @@ namespace MWGui GM_SpellCreation, GM_Enchanting, GM_Training, + GM_MerchantRepair, GM_Levelup, diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 40fcf2988a..d39ad6a5ae 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -32,20 +32,9 @@ namespace MWGui getWidget(mCancelButton, "CancelButton"); getWidget(mPlayerGold, "PlayerGold"); - getWidget(mSelect, "Select"); - getWidget(mSpells, "Spells"); getWidget(mSpellsView, "SpellsView"); mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onCancelButtonClicked); - - mSpells->setCoord(450/2-mSpells->getTextSize().width/2, - mSpells->getTop(), - mSpells->getTextSize().width, - mSpells->getHeight()); - mSelect->setCoord(8, - mSelect->getTop(), - mSelect->getTextSize().width, - mSelect->getHeight()); } void SpellBuyingWindow::addSpell(const std::string& spellId) diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index c4988fff35..f9cda35df0 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -28,8 +28,6 @@ namespace MWGui protected: MyGUI::Button* mCancelButton; MyGUI::TextBox* mPlayerGold; - MyGUI::TextBox* mSpells; - MyGUI::TextBox* mSelect; MyGUI::ScrollView* mSpellsView; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b7d6ed1c9b..07ea726206 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -55,6 +55,7 @@ #include "exposedwindow.hpp" #include "cursor.hpp" #include "spellicons.hpp" +#include "merchantrepair.hpp" using namespace MWGui; @@ -90,6 +91,7 @@ WindowManager::WindowManager( , mSpellCreationDialog(NULL) , mEnchantingDialog(NULL) , mTrainingWindow(NULL) + , mMerchantRepair(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -180,6 +182,7 @@ WindowManager::WindowManager( mSpellCreationDialog = new SpellCreationDialog(*this); mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); + mMerchantRepair = new MerchantRepair(*this); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -245,6 +248,7 @@ WindowManager::~WindowManager() delete mTrainingWindow; delete mCountDialog; delete mQuickKeysMenu; + delete mMerchantRepair; delete mCursor; cleanupGarbage(); @@ -303,6 +307,7 @@ void WindowManager::updateVisible() mSpellCreationDialog->setVisible(false); mEnchantingDialog->setVisible(false); mTrainingWindow->setVisible(false); + mMerchantRepair->setVisible(false); mHud->setVisible(mHudEnabled); @@ -428,6 +433,9 @@ void WindowManager::updateVisible() case GM_Training: mTrainingWindow->setVisible(true); break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; case GM_InterMessageBox: break; case GM_Journal: @@ -1132,6 +1140,11 @@ void WindowManager::startTraining(MWWorld::Ptr actor) mTrainingWindow->startTraining(actor); } +void WindowManager::startRepair(MWWorld::Ptr actor) +{ + mMerchantRepair->startRepair(actor); +} + const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index a7baf5207e..2242a8467b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -74,6 +74,7 @@ namespace MWGui class TrainingWindow; class Cursor; class SpellIcons; + class MerchantRepair; class WindowManager : public MWBase::WindowManager { @@ -229,6 +230,7 @@ namespace MWGui virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); + virtual void startRepair(MWWorld::Ptr actor); virtual void changePointer (const std::string& name); @@ -266,6 +268,8 @@ namespace MWGui SpellCreationDialog* mSpellCreationDialog; EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; + MerchantRepair* mMerchantRepair; + Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 3dce049f4d..223514e086 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -62,13 +62,13 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::end() 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 + /// \todo add current enchantment charge here when it is implemented if ( ptr1.mCellRef->mRefID == ptr2.mCellRef->mRefID && 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->mOwner == ptr2.mCellRef->mOwner && ptr1.mCellRef->mSoul == ptr2.mCellRef->mSoul - && ptr1.mCellRef->mCharge == ptr2.mCellRef->mCharge) + && ptr1.mCellRef->mCharge == -1) // item that is already partly used up never stacks return true; return false; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index beace5b81e..4adebf1dfd 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -78,6 +78,7 @@ set(MYGUI_FILES openmw_trainingwindow.layout openmw_travel_window.layout openmw_persuasion_dialog.layout + openmw_merchantrepair.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_merchantrepair.layout b/files/mygui/openmw_merchantrepair.layout new file mode 100644 index 0000000000..360f5f4f09 --- /dev/null +++ b/files/mygui/openmw_merchantrepair.layout @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_spell_buying_window.layout b/files/mygui/openmw_spell_buying_window.layout index 1e18fda236..c55cd0e22d 100644 --- a/files/mygui/openmw_spell_buying_window.layout +++ b/files/mygui/openmw_spell_buying_window.layout @@ -5,13 +5,13 @@ - - + + - - - + + + From 78f3f19f62393d5d256657b8aa8c60e1eb94058a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 22 Mar 2013 14:28:50 +0100 Subject: [PATCH 0113/1537] Thrown weapons, arrows and bolts shouldn't have item health --- apps/openmw/mwclass/weapon.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index e9e42d3fdd..a6a8e631b3 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -75,7 +75,10 @@ namespace MWClass bool Weapon::hasItemHealth (const MWWorld::Ptr& ptr) const { - return true; + MWWorld::LiveCellRef *ref = + ptr.get(); + + return (ref->mBase->mData.mType < 11); // thrown weapons and arrows/bolts don't have health, only quantity } int Weapon::getItemMaxHealth (const MWWorld::Ptr& ptr) const From df8600e636082eb6c7821c51b7dd49ac1062e0d7 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 22 Mar 2013 18:06:11 +0100 Subject: [PATCH 0114/1537] New anvil icon (repair.svg), edited weapon.svg (added new gradient on dagger blade) and light source.svg (clear to see what happend). container icon is still work in progress. --- .../light source.svg | 136 +- .../referenceable record type/repair.svg | 1280 +++++++++++++++++ .../referenceable record type/weapon.svg | 37 +- 3 files changed, 1367 insertions(+), 86 deletions(-) create mode 100644 files/opencs/scalable/referenceable record type/repair.svg diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg index 8575659f45..f8f5066365 100644 --- a/files/opencs/scalable/referenceable record type/light source.svg +++ b/files/opencs/scalable/referenceable record type/light source.svg @@ -23,11 +23,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="5.12" - inkscape:cx="-14.844087" - inkscape:cy="12.523576" + inkscape:zoom="7.2407734" + inkscape:cx="15.039623" + inkscape:cy="28.976292" inkscape:document-units="px" - inkscape:current-layer="g4512" + inkscape:current-layer="g6692" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -45,9 +45,9 @@ inkscape:object-paths="true" inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" - inkscape:snap-global="true" + inkscape:snap-global="false" inkscape:snap-smooth-nodes="false" - inkscape:snap-grids="false" + inkscape:snap-grids="true" inkscape:snap-nodes="true"> + + + + + + + + + - - - @@ -1448,29 +1441,14 @@ - - + d="m 32.999997,6.5 a 6.4999967,2.5 0 1 1 -12.999994,0 6.4999967,2.5 0 1 1 12.999994,0 z" + transform="matrix(1.2476493,0,0,1.1773057,-95.452015,955.91965)" /> - + width="1.1570125" + height="2.2736316" + x="-62.967812" + y="961.29846" /> + d="m -50.291451,955.99365 c -0.306142,0.58022 -0.173213,1.37959 -0.741985,1.81489 -0.555003,0.71326 -0.773186,1.6155 -1.259884,2.37061 -0.545654,1.01279 -0.9642,2.21153 -0.612129,3.35954 0.288553,1.36917 0.604843,2.81123 1.512357,3.91947 0.601372,0.6775 1.7644,0.89162 2.455823,0.22684 0.753966,-0.66641 1.219278,-1.61104 1.490732,-2.56706 0.268644,-1.09118 0.258571,-2.22309 0.405108,-3.33193 0.004,-0.92336 -0.539155,-1.718 -0.841509,-2.56039 -0.468277,-1.04235 -0.941776,-2.14938 -1.812123,-2.9223 -0.181111,-0.13328 -0.382557,-0.23957 -0.59639,-0.30967 z" + style="fill:#ffcb80;fill-opacity:1;stroke:none;filter:url(#filter4579)" + transform="matrix(1.1359383,0,0,1.1359383,-5.573807,-136.87442)" /> - + d="m -50.089487,965.64147 c -0.06194,0.11739 -0.03504,0.2791 -0.150109,0.36717 -0.11228,0.14429 -0.15642,0.32682 -0.254882,0.47959 -0.110389,0.20489 -0.195064,0.4474 -0.123837,0.67965 0.05838,0.27699 0.122363,0.56873 0.305959,0.79293 0.121661,0.13707 0.356949,0.18038 0.496828,0.0459 0.152532,-0.13481 0.246667,-0.32592 0.301584,-0.51933 0.05435,-0.22075 0.05231,-0.44974 0.08196,-0.67406 8.27e-4,-0.18681 -0.109074,-0.34757 -0.170242,-0.51799 -0.09474,-0.21087 -0.190528,-0.43483 -0.366604,-0.5912 -0.03664,-0.0269 -0.07739,-0.0485 -0.120653,-0.0626 z" + style="fill:#ffffff;fill-opacity:1;stroke:none;filter:url(#filter4575)" + transform="matrix(1.1359383,0,0,1.1359383,-5.573807,-136.87442)" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg index 1e5aaac41c..2e832fff76 100644 --- a/files/opencs/scalable/referenceable record type/weapon.svg +++ b/files/opencs/scalable/referenceable record type/weapon.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="3.6203867" - inkscape:cx="-21.028476" - inkscape:cy="-1.6134251" + inkscape:zoom="5.12" + inkscape:cx="13.777504" + inkscape:cy="9.2319835" inkscape:document-units="px" inkscape:current-layer="g5966" showgrid="true" @@ -56,6 +56,17 @@ + + + + + @@ -1170,6 +1190,17 @@ d="m -69.333164,982.81214 0,3.65905 -6.823877,0 11.138217,11.04103 11.138216,-11.04103 -6.823877,0 0,-3.65905 -8.628679,0 z" id="path5146" inkscape:connector-curvature="0" /> + + + + From a2ca679beb294140710a5dd1b0e2b273405db8a0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Mar 2013 08:16:46 +0100 Subject: [PATCH 0115/1537] Added PC repair feature --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwbase/windowmanager.hpp | 1 + apps/openmw/mwclass/repair.cpp | 19 +++ apps/openmw/mwclass/repair.hpp | 12 ++ apps/openmw/mwgui/repair.cpp | 157 +++++++++++++++++++++++++ apps/openmw/mwgui/repair.hpp | 46 ++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 + apps/openmw/mwmechanics/repair.cpp | 110 +++++++++++++++++ apps/openmw/mwmechanics/repair.hpp | 23 ++++ apps/openmw/mwworld/actionrepair.cpp | 18 +++ apps/openmw/mwworld/actionrepair.hpp | 17 +++ apps/openmw/mwworld/containerstore.cpp | 24 ++-- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_repair.layout | 33 ++++++ files/mygui/openmw_text.skin.xml | 4 +- 16 files changed, 469 insertions(+), 18 deletions(-) create mode 100644 apps/openmw/mwgui/repair.cpp create mode 100644 apps/openmw/mwgui/repair.hpp create mode 100644 apps/openmw/mwmechanics/repair.cpp create mode 100644 apps/openmw/mwmechanics/repair.hpp create mode 100644 apps/openmw/mwworld/actionrepair.cpp create mode 100644 apps/openmw/mwworld/actionrepair.hpp create mode 100644 files/mygui/openmw_repair.layout diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 11c6360e57..41599b35db 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair + merchantrepair repair ) add_openmw_dir (mwdialogue @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback + esmstore store recordcmp fallback actionrepair ) add_openmw_dir (mwclass @@ -65,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate repair ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 0a6de5e14d..6760c89d07 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -239,6 +239,7 @@ namespace MWBase virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; + virtual void startRepairItem(MWWorld::Ptr item) = 0; virtual void changePointer (const std::string& name) = 0; diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index f0b6fe88d9..bafedee88b 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -12,6 +12,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/actionrepair.hpp" #include "../mwgui/tooltips.hpp" @@ -120,6 +121,19 @@ namespace MWClass return (ref->mBase->mName != ""); } + bool Repair::hasItemHealth (const MWWorld::Ptr& ptr) const + { + return true; + } + + int Repair::getItemMaxHealth (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mUses; + } + MWGui::ToolTipInfo Repair::getToolTipInfo (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = @@ -156,4 +170,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mRepairs.insert(*ref), &cell); } + + boost::shared_ptr Repair::use (const MWWorld::Ptr& ptr) const + { + return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index c58e38f96b..3083c97e35 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -49,6 +49,18 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu (default implementation: return a + /// null action). + + virtual bool hasItemHealth (const MWWorld::Ptr& ptr) const; + ///< \return Item health data available? (default implementation: false) + + virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; + ///< Return item max health or throw an exception, if class does not have item health + /// (default implementation: throw an exceoption) }; } diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp new file mode 100644 index 0000000000..f53ddc4305 --- /dev/null +++ b/apps/openmw/mwgui/repair.cpp @@ -0,0 +1,157 @@ +#include "repair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "widgets.hpp" + +namespace MWGui +{ + +Repair::Repair(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_repair.layout", parWindowManager) +{ + getWidget(mRepairBox, "RepairBox"); + getWidget(mRepairView, "RepairView"); + getWidget(mToolBox, "ToolBox"); + getWidget(mToolIcon, "ToolIcon"); + getWidget(mUsesLabel, "UsesLabel"); + getWidget(mQualityLabel, "QualityLabel"); + getWidget(mCancelButton, "CancelButton"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onCancel); +} + +void Repair::open() +{ + center(); +} + +void Repair::startRepairItem(const MWWorld::Ptr &item) +{ + mRepair.setTool(item); + + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(item).getInventoryIcon(item); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + mToolIcon->setImageTexture (path); + mToolIcon->setUserString("ToolTipType", "ItemPtr"); + mToolIcon->setUserData(item); + + updateRepairView(); +} + +void Repair::updateRepairView() +{ + MWWorld::LiveCellRef *ref = + mRepair.getTool().get(); + + int uses = (mRepair.getTool().getCellRef().mCharge != -1) ? mRepair.getTool().getCellRef().mCharge : ref->mBase->mData.mUses; + + float quality = ref->mBase->mData.mQuality; + + std::stringstream qualityStr; + qualityStr << std::setprecision(3) << quality; + + mUsesLabel->setCaptionWithReplacing("#{sUses} " + boost::lexical_cast(uses)); + mQualityLabel->setCaptionWithReplacing("#{sQuality} " + qualityStr.str()); + + bool toolBoxVisible = (mRepair.getTool().getRefData().getCount() != 0); + mToolBox->setVisible(toolBoxVisible); + + bool toolBoxWasVisible = (mRepairBox->getPosition().top != mToolBox->getPosition().top); + + if (toolBoxVisible && !toolBoxWasVisible) + { + // shrink + mRepairBox->setPosition(mRepairBox->getPosition() + MyGUI::IntPoint(0,mToolBox->getSize().height)); + mRepairBox->setSize(mRepairBox->getSize() - MyGUI::IntSize(0,mToolBox->getSize().height)); + } + else if (!toolBoxVisible && toolBoxWasVisible) + { + // expand + mRepairBox->setPosition(MyGUI::IntPoint (mRepairBox->getPosition().left, mToolBox->getPosition().top)); + mRepairBox->setSize(mRepairBox->getSize() + MyGUI::IntSize(0,mToolBox->getSize().height)); + } + + while (mRepairView->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mRepairView->getChildAt(0)); + + int currentY = 0; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; + for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); + iter!=store.end(); ++iter) + { + if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) + { + int maxDurability = MWWorld::Class::get(*iter).getItemMaxHealth(*iter); + int durability = (iter->getCellRef().mCharge == -1) ? maxDurability : iter->getCellRef().mCharge; + if (maxDurability == durability) + continue; + + MyGUI::TextBox* text = mRepairView->createWidget ( + "SandText", MyGUI::IntCoord(8, currentY, mRepairView->getWidth()-8, 18), MyGUI::Align::Default); + text->setCaption(MWWorld::Class::get(*iter).getName(*iter)); + text->setNeedMouseFocus(false); + currentY += 19; + + MyGUI::ImageBox* icon = mRepairView->createWidget ( + "ImageBox", MyGUI::IntCoord(16, currentY, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + icon->setImageTexture (path); + icon->setUserString("ToolTipType", "ItemPtr"); + icon->setUserData(*iter); + icon->eventMouseButtonClick += MyGUI::newDelegate(this, &Repair::onRepairItem); + icon->eventMouseWheel += MyGUI::newDelegate(this, &Repair::onMouseWheel); + + Widgets::MWDynamicStatPtr chargeWidget = mRepairView->createWidget + ("MW_ChargeBar", MyGUI::IntCoord(72, currentY+2, 199, 20), MyGUI::Align::Default); + chargeWidget->setValue(durability, maxDurability); + chargeWidget->setNeedMouseFocus(false); + + currentY += 32 + 4; + } + } + mRepairView->setCanvasSize (MyGUI::IntSize(mRepairView->getWidth(), std::max(mRepairView->getHeight(), currentY))); +} + +void Repair::onCancel(MyGUI::Widget *sender) +{ + mWindowManager.removeGuiMode(GM_Repair); +} + +void Repair::onRepairItem(MyGUI::Widget *sender) +{ + if (!mRepair.getTool().getRefData().getCount()) + return; + + mRepair.repair(*sender->getUserData()); + + updateRepairView(); +} + +void Repair::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mRepairView->getViewOffset().top + _rel*0.3 > 0) + mRepairView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mRepairView->setViewOffset(MyGUI::IntPoint(0, mRepairView->getViewOffset().top + _rel*0.3)); +} + +} diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp new file mode 100644 index 0000000000..c14b1955bd --- /dev/null +++ b/apps/openmw/mwgui/repair.hpp @@ -0,0 +1,46 @@ +#ifndef OPENMW_MWGUI_REPAIR_H +#define OPENMW_MWGUI_REPAIR_H + +#include "window_base.hpp" + +#include "../mwworld/ptr.hpp" +#include "../mwmechanics/repair.hpp" + +namespace MWGui +{ + +class Repair : public WindowBase +{ +public: + Repair(MWBase::WindowManager &parWindowManager); + + virtual void open(); + + void startRepairItem (const MWWorld::Ptr& item); + +protected: + MyGUI::Widget* mRepairBox; + MyGUI::ScrollView* mRepairView; + + MyGUI::Widget* mToolBox; + + MyGUI::ImageBox* mToolIcon; + + MyGUI::TextBox* mUsesLabel; + MyGUI::TextBox* mQualityLabel; + + MyGUI::Button* mCancelButton; + + MWMechanics::Repair mRepair; + + void updateRepairView(); + + void onRepairItem (MyGUI::Widget* sender); + void onCancel (MyGUI::Widget* sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + +}; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 07ea726206..718bb7106e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -56,6 +56,7 @@ #include "cursor.hpp" #include "spellicons.hpp" #include "merchantrepair.hpp" +#include "repair.hpp" using namespace MWGui; @@ -92,6 +93,7 @@ WindowManager::WindowManager( , mEnchantingDialog(NULL) , mTrainingWindow(NULL) , mMerchantRepair(NULL) + , mRepair(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -183,6 +185,7 @@ WindowManager::WindowManager( mEnchantingDialog = new EnchantingDialog(*this); mTrainingWindow = new TrainingWindow(*this); mMerchantRepair = new MerchantRepair(*this); + mRepair = new Repair(*this); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -249,6 +252,7 @@ WindowManager::~WindowManager() delete mCountDialog; delete mQuickKeysMenu; delete mMerchantRepair; + delete mRepair; delete mCursor; cleanupGarbage(); @@ -308,6 +312,7 @@ void WindowManager::updateVisible() mEnchantingDialog->setVisible(false); mTrainingWindow->setVisible(false); mMerchantRepair->setVisible(false); + mRepair->setVisible(false); mHud->setVisible(mHudEnabled); @@ -436,6 +441,9 @@ void WindowManager::updateVisible() case GM_MerchantRepair: mMerchantRepair->setVisible(true); break; + case GM_Repair: + mRepair->setVisible(true); + break; case GM_InterMessageBox: break; case GM_Journal: @@ -1145,6 +1153,11 @@ void WindowManager::startRepair(MWWorld::Ptr actor) mMerchantRepair->startRepair(actor); } +void WindowManager::startRepairItem(MWWorld::Ptr item) +{ + mRepair->startRepairItem(item); +} + const Translation::Storage& WindowManager::getTranslationDataStorage() const { return mTranslationDataStorage; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 2242a8467b..216ab9a6f8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -75,6 +75,7 @@ namespace MWGui class Cursor; class SpellIcons; class MerchantRepair; + class Repair; class WindowManager : public MWBase::WindowManager { @@ -231,6 +232,7 @@ namespace MWGui virtual void startEnchanting(MWWorld::Ptr actor); virtual void startTraining(MWWorld::Ptr actor); virtual void startRepair(MWWorld::Ptr actor); + virtual void startRepairItem(MWWorld::Ptr item); virtual void changePointer (const std::string& name); @@ -269,6 +271,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; MerchantRepair* mMerchantRepair; + Repair* mRepair; Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwmechanics/repair.cpp b/apps/openmw/mwmechanics/repair.cpp new file mode 100644 index 0000000000..8ed4498859 --- /dev/null +++ b/apps/openmw/mwmechanics/repair.cpp @@ -0,0 +1,110 @@ +#include "repair.hpp" + +#include + +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" + +namespace MWMechanics +{ + +void Repair::repair(const MWWorld::Ptr &itemToRepair) +{ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::LiveCellRef *ref = + mTool.get(); + + // reduce number of uses left + int uses = (mTool.getCellRef().mCharge != -1) ? mTool.getCellRef().mCharge : ref->mBase->mData.mUses; + mTool.getCellRef().mCharge = uses-1; + + // unstack tool if required + if (mTool.getRefData().getCount() > 1 && uses == ref->mBase->mData.mUses) + { + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + MWWorld::ContainerStoreIterator it = store.add(mTool); + it->getRefData().setCount(mTool.getRefData().getCount()-1); + it->getCellRef().mCharge = -1; + + mTool.getRefData().setCount(1); + } + + MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats(player); + + float fatigueTerm = stats.getFatigueTerm(); + int pcStrength = stats.getAttribute(ESM::Attribute::Strength).getModified(); + int pcLuck = stats.getAttribute(ESM::Attribute::Luck).getModified(); + int armorerSkill = npcStats.getSkill(ESM::Skill::Armorer).getModified(); + + float fRepairAmountMult = MWBase::Environment::get().getWorld()->getStore().get() + .find("fRepairAmountMult")->getFloat(); + + float toolQuality = ref->mBase->mData.mQuality; + + float x = (0.1 * pcStrength + 0.1 * pcLuck + armorerSkill) * fatigueTerm; + + int roll = static_cast (std::rand()) / RAND_MAX * 100; + if (roll <= x) + { + int y = fRepairAmountMult * toolQuality * roll; + y = std::max(1, y); + + // repair by 'y' points + itemToRepair.getCellRef().mCharge += y; + itemToRepair.getCellRef().mCharge = std::min(itemToRepair.getCellRef().mCharge, + MWWorld::Class::get(itemToRepair).getItemMaxHealth(itemToRepair)); + + // set the OnPCRepair variable on the item's script + std::string script = MWWorld::Class::get(itemToRepair).getScript(itemToRepair); + if(script != "") + itemToRepair.getRefData().getLocals().setVarByInt(script, "onpcrepair", 1); + + // increase skill + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Armorer, 0); + + MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); + MWBase::Environment::get().getWindowManager()->messageBox("#{sRepairSuccess}"); + } + else + { + MWBase::Environment::get().getSoundManager()->playSound("Repair Fail",1,1); + MWBase::Environment::get().getWindowManager()->messageBox("#{sRepairFailed}"); + } + + // tool used up? + if (mTool.getCellRef().mCharge == 0) + { + mTool.getRefData().setCount(0); + + std::string message = MWBase::Environment::get().getWorld()->getStore().get() + .find("sNotifyMessage51")->getString(); + + MWBase::Environment::get().getWindowManager()->messageBox((boost::format(message) % MWWorld::Class::get(mTool).getName(mTool)).str()); + + // try to find a new tool of the same ID + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + for (MWWorld::ContainerStoreIterator iter (store.begin()); + iter!=store.end(); ++iter) + { + if (Misc::StringUtils::ciEqual(iter->getCellRef().mRefID, mTool.getCellRef().mRefID)) + { + mTool = *iter; + break; + } + } + } +} + +} diff --git a/apps/openmw/mwmechanics/repair.hpp b/apps/openmw/mwmechanics/repair.hpp new file mode 100644 index 0000000000..6f9a866af1 --- /dev/null +++ b/apps/openmw/mwmechanics/repair.hpp @@ -0,0 +1,23 @@ +#ifndef OPENMW_MWMECHANICS_REPAIR_H +#define OPENMW_MWMECHANICS_REPAIR_H + +#include "../mwworld/ptr.hpp" + +namespace MWMechanics +{ + + class Repair + { + public: + void setTool (const MWWorld::Ptr& tool) { mTool = tool; } + MWWorld::Ptr getTool() { return mTool; } + + void repair (const MWWorld::Ptr& itemToRepair); + + private: + MWWorld::Ptr mTool; + }; + +} + +#endif diff --git a/apps/openmw/mwworld/actionrepair.cpp b/apps/openmw/mwworld/actionrepair.cpp new file mode 100644 index 0000000000..bd56421165 --- /dev/null +++ b/apps/openmw/mwworld/actionrepair.cpp @@ -0,0 +1,18 @@ +#include "actionrepair.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + +namespace MWWorld +{ + ActionRepair::ActionRepair(const Ptr &item) + : Action(false, item) + { + } + + void ActionRepair::executeImp (const Ptr& actor) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Repair); + MWBase::Environment::get().getWindowManager()->startRepairItem(getTarget()); + } +} diff --git a/apps/openmw/mwworld/actionrepair.hpp b/apps/openmw/mwworld/actionrepair.hpp new file mode 100644 index 0000000000..1d3ef2bc11 --- /dev/null +++ b/apps/openmw/mwworld/actionrepair.hpp @@ -0,0 +1,17 @@ +#ifndef GAME_MWWORLD_ACTIONREPAIR_H +#define GAME_MWWORLD_ACTIONREPAIR_H + +#include "action.hpp" + +namespace MWWorld +{ + class ActionRepair : public Action + { + virtual void executeImp (const Ptr& actor); + + public: + ActionRepair(const MWWorld::Ptr& item); + }; +} + +#endif diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 223514e086..ac27beb44a 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -38,12 +38,6 @@ namespace return sum; } - - bool compare_string_ci(std::string str1, std::string str2) - { - Misc::StringUtils::toLower(str1); - return str1 == str2; - } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -68,7 +62,11 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) && 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->mOwner == ptr2.mCellRef->mOwner && ptr1.mCellRef->mSoul == ptr2.mCellRef->mSoul - && ptr1.mCellRef->mCharge == -1) // item that is already partly used up never stacks + // item that is already partly used up never stacks + && (!MWWorld::Class::get(ptr1).hasItemHealth(ptr1) || ptr1.mCellRef->mCharge == -1 + || MWWorld::Class::get(ptr1).getItemMaxHealth(ptr1) == ptr1.mCellRef->mCharge) + && (!MWWorld::Class::get(ptr2).hasItemHealth(ptr2) || ptr2.mCellRef->mCharge == -1 + || MWWorld::Class::get(ptr2).getItemMaxHealth(ptr2) == ptr2.mCellRef->mCharge)) return true; return false; @@ -118,11 +116,11 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) MWWorld::LiveCellRef *gold = ptr.get(); - if (compare_string_ci(gold->mRef.mRefID, "gold_001") - || compare_string_ci(gold->mRef.mRefID, "gold_005") - || compare_string_ci(gold->mRef.mRefID, "gold_010") - || compare_string_ci(gold->mRef.mRefID, "gold_025") - || compare_string_ci(gold->mRef.mRefID, "gold_100")) + if (Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_001") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_005") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_010") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_025") + || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_100")) { MWWorld::ManualRef ref(esmStore, "Gold_001"); @@ -130,7 +128,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - if (compare_string_ci((*iter).get()->mRef.mRefID, "gold_001")) + if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) { (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); flagAsModified(); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 4adebf1dfd..7da28f0bfa 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -79,6 +79,7 @@ set(MYGUI_FILES openmw_travel_window.layout openmw_persuasion_dialog.layout openmw_merchantrepair.layout + openmw_repair.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_repair.layout b/files/mygui/openmw_repair.layout new file mode 100644 index 0000000000..2881a5853a --- /dev/null +++ b/files/mygui/openmw_repair.layout @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 13b22ff93d..71e86091c8 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -154,8 +154,8 @@ - - + + From 7beda509fe711190fb952ad33c784c1d1557eba3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 23 Mar 2013 09:53:38 +0100 Subject: [PATCH 0116/1537] Lighting should be done in view space instead of object space, so that attenuation also works correctly for scaled objects --- files/materials/objects.shader | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 46e3abeb3c..ae589a05be 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -54,10 +54,11 @@ #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) - shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_object_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) #if VERTEXCOLOR_MODE != 2 shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) #endif @@ -131,11 +132,14 @@ #if VERTEX_LIGHTING + float3 viewPos = shMatrixMult(worldView, shInputPosition).xyz; + float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); + float3 lightDir; float d; lightResult = float4(0,0,0,1); @shForeach(@shGlobalSettingString(num_lights)) - lightDir = lightPosition[@shIterator].xyz - (shInputPosition.xyz * lightPosition[@shIterator].w); + lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); d = length(lightDir); lightDir = normalize(lightDir); @@ -143,11 +147,11 @@ #if VERTEXCOLOR_MODE == 2 lightResult.xyz += colour.xyz * lightDiffuse[@shIterator].xyz * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normalize(normal.xyz), normalize(lightDir)), 0); + * max(dot(viewNormal.xyz, lightDir), 0); #else lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) - * max(dot(normalize(normal.xyz), normalize(lightDir)), 0); + * max(dot(viewNormal.xyz, lightDir), 0); #endif #if @shIterator == 0 From 92f00989110bf3371f9be5ffe6b79f8903858c02 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Mar 2013 13:13:34 +0100 Subject: [PATCH 0117/1537] added new constructors for EnumDelegateFactory --- apps/opencs/view/world/enumdelegate.cpp | 11 +++++++++++ apps/opencs/view/world/enumdelegate.hpp | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 7a8b45373d..0dd0a1d594 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -1,6 +1,7 @@ #include "enumdelegate.hpp" +#include #include #include @@ -89,6 +90,16 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte } +CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} + +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names) +{ + assert (names); + + for (int i=0; names[i]; ++i) + add (i, names[i]); +} + CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, QObject *parent) const { diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index f11252371e..752ed5be72 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -45,6 +45,11 @@ namespace CSVWorld public: + EnumDelegateFactory(); + + EnumDelegateFactory (const char **names); + ///< \param names Array of char pointer with a 0-pointer as end mark + virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. From 0ce962e815bb0f08e2ddfbf576efa216da2b1aa7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 23 Mar 2013 13:13:53 +0100 Subject: [PATCH 0118/1537] added specialisation column to skill table --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/doc/viewmanager.cpp | 8 ++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index c44abda2b2..a098fcb7e5 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -31,7 +31,8 @@ namespace CSMWorld Display_Float, Display_Var, Display_GmstVarType, - Display_GlobalVarType + Display_GlobalVarType, + Display_Specialisation }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index a84c9ddf64..43aad889d9 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -202,6 +202,31 @@ namespace CSMWorld return true; } }; + + template + struct SpecialisationColumn : public Column + { + SpecialisationColumn() : Column ("Specialisation", ColumnBase::Display_Specialisation) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mSpecialization; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mSpecialization = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 51ea3e71be..de85beed45 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -38,6 +38,7 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new SpecialisationColumn); mSkills.addColumn (new DescriptionColumn); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 33300f67a7..f59be3d997 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -38,6 +38,11 @@ void CSVDoc::ViewManager::updateIndices() CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) : mDocumentManager (documentManager), mExitOnSaveStateChange(false), mUserWarned(false) { + static const char *sSpecialisations[] = + { + "Combat", "Magic", "Stealth", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -45,6 +50,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation, + new CSVWorld::EnumDelegateFactory (sSpecialisations)); } CSVDoc::ViewManager::~ViewManager() From 001b56714a2da5efdbe940b5a06645a5fa863596 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 16:16:23 +0100 Subject: [PATCH 0119/1537] Adding new status icons svg files. Qt svg does not allow blur to be used so I think that we should make png files of it but first information on the actual resolution needed is required... --- files/opencs/scalable/status/.directory | 5 + files/opencs/scalable/status/added.svg | 917 ++++++++++++++++ files/opencs/scalable/status/modified.svg | 1197 +++++++++++++++++++++ files/opencs/scalable/status/removed.svg | 1088 +++++++++++++++++++ 4 files changed, 3207 insertions(+) create mode 100644 files/opencs/scalable/status/.directory create mode 100644 files/opencs/scalable/status/added.svg create mode 100644 files/opencs/scalable/status/modified.svg create mode 100644 files/opencs/scalable/status/removed.svg diff --git a/files/opencs/scalable/status/.directory b/files/opencs/scalable/status/.directory new file mode 100644 index 0000000000..e2d80ed58c --- /dev/null +++ b/files/opencs/scalable/status/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg new file mode 100644 index 0000000000..a5767d23b3 --- /dev/null +++ b/files/opencs/scalable/status/added.svg @@ -0,0 +1,917 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg new file mode 100644 index 0000000000..c8b56cd049 --- /dev/null +++ b/files/opencs/scalable/status/modified.svg @@ -0,0 +1,1197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/removed.svg b/files/opencs/scalable/status/removed.svg new file mode 100644 index 0000000000..719035be9e --- /dev/null +++ b/files/opencs/scalable/status/removed.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + From 962b5041296cdf3a0422b9f0c0f29e49a5f2bd5f Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Sat, 23 Mar 2013 16:20:10 +0100 Subject: [PATCH 0120/1537] add dpkg information for mwiniimporter, this blocked debian/ubuntu buildd from building --- apps/mwiniimporter/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/mwiniimporter/CMakeLists.txt b/apps/mwiniimporter/CMakeLists.txt index deab88ce28..702f665138 100644 --- a/apps/mwiniimporter/CMakeLists.txt +++ b/apps/mwiniimporter/CMakeLists.txt @@ -22,3 +22,8 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(mwiniimport gcov) endif() + +if(DPKG_PROGRAM) + INSTALL(TARGETS mwiniimport RUNTIME DESTINATION games COMPONENT mwiniimport) +endif() + From 43e863b0207396bf68ce868c11077cb7ba3f3b54 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 16:22:17 +0100 Subject: [PATCH 0121/1537] Forgot to place the icons in the middle of the page. --- files/opencs/scalable/status/modified.svg | 67 ++----------------- files/opencs/scalable/status/removed.svg | 80 +++-------------------- 2 files changed, 13 insertions(+), 134 deletions(-) diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg index c8b56cd049..3b183e314e 100644 --- a/files/opencs/scalable/status/modified.svg +++ b/files/opencs/scalable/status/modified.svg @@ -24,8 +24,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="3.6203867" - inkscape:cx="-21.788854" - inkscape:cy="23.355872" + inkscape:cx="-39.987384" + inkscape:cy="43.542041" inkscape:document-units="px" inkscape:current-layer="g5966" showgrid="true" @@ -985,16 +985,6 @@ fx="-97.089668" fy="-33.913769" r="20" /> - - - - - - @@ -1140,7 +1083,7 @@ transform="matrix(0.97772023,0,0,0.97772023,100.68016,77.074325)"> - - - - - - - - + transform="matrix(0,1,-1,0,0.20564565,0.22375836)" /> + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4.5731945;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" /> + transform="matrix(0,1,-1,0,0.20564565,0.22375836)" /> From 59233e54b2083afd72d250928e7060de0d2a3419 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 18:18:19 +0100 Subject: [PATCH 0122/1537] changing potion.svg according to pvdk sugestions --- .../referenceable record type/potion.svg | 162 +++++++++++------- 1 file changed, 104 insertions(+), 58 deletions(-) diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg index 8880065312..612f45aa42 100644 --- a/files/opencs/scalable/referenceable record type/potion.svg +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -24,10 +24,10 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="7.2407734" - inkscape:cx="18.842132" - inkscape:cy="26.695499" + inkscape:cx="3.6117613" + inkscape:cy="14.120537" inkscape:document-units="px" - inkscape:current-layer="g5966" + inkscape:current-layer="g3910" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -55,6 +55,32 @@ + + + + + + + + + - + offset="0" + style="stop-color:#8cf0eb;stop-opacity:0.78431374;" /> @@ -930,22 +952,12 @@ fx="-150.6485" fy="-33.680485" r="19.749271" /> - + xlink:href="#linearGradient3853" + id="radialGradient3918" + cx="0.20415781" + cy="26.466549" + fx="0.20415781" + fy="26.466549" + r="15.52295" + gradientTransform="matrix(1.3421662,-1.1488417,0.96457332,1.1859542,-25.598784,-3.3438458)" + gradientUnits="userSpaceOnUse" /> + + + xlink:href="#linearGradient4535" + id="radialGradient4543" + cx="15.546875" + cy="24" + fx="15.546875" + fy="24" + r="15.52295" + gradientTransform="matrix(0.99999999,-0.04184496,0.06136199,1.5432733,-1.4726875,-12.388)" + gradientUnits="userSpaceOnUse" /> @@ -1017,30 +1047,46 @@ sodipodi:ry="4.4194174" d="m -133.13494,-22.158251 c 0,2.440777 -8.84205,4.419418 -19.74928,4.419418 -10.90722,0 -19.74927,-1.978641 -19.74927,-4.419418 0,-2.440777 8.84205,-4.419417 19.74927,-4.419417 10.90723,0 19.74928,1.97864 19.74928,4.419417 z" transform="matrix(0.92927807,0,0,1.0003876,63.663518,999.66077)" /> - + + + + + + - - Date: Sat, 23 Mar 2013 19:29:52 +0100 Subject: [PATCH 0123/1537] Drawer as container icon. Look a little better the old crappy chest but changes are needed. --- .../referenceable record type/container.svg | 2217 +++++++++-------- 1 file changed, 1223 insertions(+), 994 deletions(-) diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg index 11ad794384..2a93954bd0 100644 --- a/files/opencs/scalable/referenceable record type/container.svg +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="11.313709" - inkscape:cx="20.32374" - inkscape:cy="21.784699" + inkscape:zoom="8.0000004" + inkscape:cx="7.2255179" + inkscape:cy="2.9394873" inkscape:document-units="px" inkscape:current-layer="g9364" showgrid="true" @@ -43,1219 +43,1477 @@ inkscape:snap-bbox-edge-midpoints="false" inkscape:snap-bbox-midpoints="false" inkscape:object-paths="true" - inkscape:snap-intersection-paths="false" + inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" inkscape:snap-global="true" - inkscape:snap-smooth-nodes="false" + inkscape:snap-smooth-nodes="true" inkscape:snap-grids="false" inkscape:snap-nodes="true" inkscape:snap-midpoints="false"> + type="xygrid" + id="grid3225" /> + + + + + id="linearGradient6181" + inkscape:collect="always"> + style="stop-color:#232323;stop-opacity:1;" /> + + + + + + + + + + + + + + style="stop-color:#000000;stop-opacity:1;" /> + + + + + + + + + + + + + + + + + + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#002bf4;stop-opacity:1;" /> + style="stop-color:#ffcb80;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:1;" /> + id="stop8862" /> + id="stop8864" /> + id="stop8852" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + id="stop8834" /> + id="stop8836" /> + id="stop4482" /> + id="stop4484" /> + inkscape:collect="always" + id="linearGradient3882"> + id="stop3884" /> + id="stop3886" /> + id="stop3941" /> + id="stop3943" /> + id="stop3881" /> + id="stop3883" /> + id="stop3869" /> + id="stop3871" /> + id="stop3855" /> + style="stop-color:#caf8db;stop-opacity:0.58823532;" /> + id="stop3857" /> + id="stop3847" /> + id="stop3849" /> + id="stop3839" /> + id="stop3841" /> + inkscape:collect="always" + id="linearGradient5958"> + id="stop5960" /> + id="stop5962" /> + id="stop5924" /> + id="stop5926" /> + style="stop-color:#000000;stop-opacity:1;" /> + id="stop6825" /> + style="stop-color:#3c3c3c;stop-opacity:0;" /> + style="stop-color:#204a87;stop-opacity:1;" /> + style="stop-color:#729fcf;stop-opacity:1;" /> + style="stop-color:#ffffff;stop-opacity:0.78431374;" /> + style="stop-color:#ffffff;stop-opacity:0;" /> + style="stop-color:#99bbd4;stop-opacity:1;" /> + style="stop-color:#5d93ba;stop-opacity:1;" /> + style="stop-color:#a6c4d9;stop-opacity:0.78431374;" /> + style="stop-color:#75a3c3;stop-opacity:1;" /> - + - - - - - - - - - - - - - + + + + + + + + + + + + + + id="stop3820" /> + id="stop3822" /> + fx="-171.01654" + cy="123.88583" + cx="-171.01654" + gradientTransform="matrix(0.23290796,0.98292589,-1.5211573,0.36044393,244.44953,1091.8596)" + gradientUnits="userSpaceOnUse" + id="radialGradient5639" + xlink:href="#linearGradient3715-2" + inkscape:collect="always" /> + id="stop3717-4" /> + id="stop3719-9" /> + fx="-182.4375" + cy="116.19179" + cx="-182.4375" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,227.36718,1219.3395)" + gradientUnits="userSpaceOnUse" + id="radialGradient5641" + xlink:href="#linearGradient5299" + inkscape:collect="always" /> + id="stop5301" /> + id="stop5303" /> + fx="-172.875" + cy="119.59179" + cx="-172.875" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,240.54684,45.0811)" + gradientUnits="userSpaceOnUse" + id="radialGradient6812" + xlink:href="#linearGradient3715-2" + inkscape:collect="always" /> + x2="26.643335" + y1="39.630547" + x1="27.183681" + id="linearGradient6823" + xlink:href="#linearGradient6815" + inkscape:collect="always" + gradientTransform="translate(8.4245144,951.32919)" /> + + + + + - - - - - - + gradientTransform="matrix(-0.28231332,0,0,0.28231332,64.982195,664.15172)" + x1="63.765881" + y1="941.44623" + x2="63.765881" + y2="965.56183" /> + + style="stop-color:#000000;stop-opacity:1;" /> + id="stop6825-9" /> + style="stop-color:#3c3c3c;stop-opacity:0;" /> + fx="-172.875" + cy="119.59179" + cx="-172.875" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,158.26577,1130.8958)" + gradientUnits="userSpaceOnUse" + id="radialGradient5639-0" + xlink:href="#linearGradient3715-2-4" + inkscape:collect="always" /> + id="stop3717-4-8" /> + id="stop3719-9-7" /> + fx="-182.4375" + cy="116.19179" + cx="-182.4375" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,218.94267,1272.3725)" + gradientUnits="userSpaceOnUse" + id="radialGradient5641-1" + xlink:href="#linearGradient5299-7" + inkscape:collect="always" /> + id="stop5301-2" /> + id="stop5303-7" /> - + - + + id="radialGradient5964" + cx="-103.70541" + cy="-39.275696" + fx="-103.70541" + fy="-39.275696" + r="20.15" + gradientTransform="matrix(0.61309318,1.698523,-1.2180273,0.43965501,-77.239822,152.43381)" + gradientUnits="userSpaceOnUse" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + y1="-45.656265" + x2="-72.843758" + y2="-45.944225" + gradientTransform="matrix(0.91762814,0,0,1.0003875,-5.0078269,1004.2961)" /> - + + + + id="radialGradient3865" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(-0.00108712,0.18221846,-0.82985011,4.6460161e-7,-113.08325,972.23283)" + cx="-116.29909" + cy="-37.504356" + fx="-116.29909" + fy="-37.504356" + r="20" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="stop4678" /> + id="stop4680" /> + id="stop4693" /> + id="stop4695" /> + id="stop4715" /> + style="stop-color:#707070;stop-opacity:0;" /> + id="stop4717" /> + id="stop4725" /> + id="stop4727" /> + id="stop4655" /> + id="stop4657" /> - - - - - - - - - - - - - - - + y1="1139.3492" + x1="203.09436" + id="linearGradient9295" + xlink:href="#linearGradient9289" + inkscape:collect="always" /> + gradientUnits="userSpaceOnUse" + y2="1151.9221" + x2="127.51315" + y1="1154.9745" + x1="124.46073" + id="linearGradient9311" + xlink:href="#linearGradient9305" + inkscape:collect="always" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1270,90 +1528,61 @@ + inkscape:groupmode="layer" + inkscape:label="Livello 1"> + transform="matrix(0.29626046,0,0,0.29626046,-45.835699,695.27639)" + id="g8044"> - + transform="translate(1.4700294,-5.8981036)" + id="g9364"> - - - - - - - - + transform="translate(98.027824,-15.186023)" /> - - + id="path4273" + d="m 206.47648,1074.7314 55.59925,0 0,45.7242 -55.59925,10e-5 0,-45.7243" + style="fill:url(#linearGradient6171-857-364-729);fill-opacity:1;stroke:#303030;stroke-opacity:1;stroke-width:1.01262247;stroke-miterlimit:4;stroke-dasharray:none" /> + style="fill:#452500;fill-opacity:1;fill-rule:evenodd;stroke:#303030;stroke-width:0.83544666;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + id="path2415" + d="m 169.25185,1184.8538 130.00422,0 -37.18034,-64.3982 -55.59925,0 -37.22463,64.3982 z" + inkscape:connector-curvature="0" /> + + + + id="g9321" /> From e97319c0bba33b551861183a0d5f0d799f2b978f Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sat, 23 Mar 2013 19:32:37 +0100 Subject: [PATCH 0124/1537] Drawer as container icon looks actually quite good IMHO. --- .../referenceable record type/container.svg | 183 +++++++++++++----- 1 file changed, 134 insertions(+), 49 deletions(-) diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg index 2a93954bd0..6c49737083 100644 --- a/files/opencs/scalable/referenceable record type/container.svg +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -23,11 +23,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="8.0000004" - inkscape:cx="7.2255179" - inkscape:cy="2.9394873" + inkscape:zoom="5.6568545" + inkscape:cx="-6.640249" + inkscape:cy="16.907775" inkscape:document-units="px" - inkscape:current-layer="g9364" + inkscape:current-layer="g8044" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -45,7 +45,7 @@ inkscape:object-paths="true" inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" - inkscape:snap-global="true" + inkscape:snap-global="false" inkscape:snap-smooth-nodes="true" inkscape:snap-grids="false" inkscape:snap-nodes="true" @@ -72,6 +72,18 @@ + + + + @@ -1502,7 +1514,8 @@ x1="227.6591" id="linearGradient6171-857-364-729" xlink:href="#linearGradient6165-696-389-794" - inkscape:collect="always" /> + inkscape:collect="always" + gradientTransform="matrix(0.87072097,0,0,1.0005854,30.284126,-0.66139717)" /> + + + + + + + @@ -1536,49 +1620,50 @@ transform="matrix(0.29626046,0,0,0.29626046,-45.835699,695.27639)" id="g8044"> - - - - - - - - + transform="translate(99.497853,-21.084127)" + style="fill:#ff0000;fill-opacity:1;stroke:none" + id="g3951" /> + + + + + + + Date: Sat, 23 Mar 2013 19:53:10 +0100 Subject: [PATCH 0125/1537] Update the status icons. X as removed.svg and backgrounds for status icons stolen from oxygen emblems :P It gives clear look for it. --- files/opencs/scalable/status/added.svg | 60 +- files/opencs/scalable/status/modified.svg | 60 +- files/opencs/scalable/status/removed.svg | 1065 ++++++++++----------- 3 files changed, 617 insertions(+), 568 deletions(-) diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg index a5767d23b3..e0af57002a 100644 --- a/files/opencs/scalable/status/added.svg +++ b/files/opencs/scalable/status/added.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.8284271" - inkscape:cx="6.6635778" - inkscape:cy="31.541579" + inkscape:zoom="5.6568542" + inkscape:cx="27.462558" + inkscape:cy="10.232345" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -878,6 +878,29 @@ stdDeviation="57.354192" id="feGaussianBlur4632" /> + + + + + @@ -896,6 +919,35 @@ id="layer1" inkscape:groupmode="layer" inkscape:label="Livello 1"> + + + + + + + + + + + + style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:4;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-linejoin:round" /> + + + + + @@ -1081,6 +1104,35 @@ + + + + + + + + + + + - - + inkscape:snap-nodes="true" /> + id="linearGradient3902" + inkscape:collect="always"> + + + + + + + + + + + + + + + + + - - + id="stop7491" /> - - - - + id="linearGradient6034"> + id="stop6036" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="stop6038" /> @@ -443,17 +343,6 @@ offset="1" id="stop3822" /> - - - - - - - + id="linearGradient3955-87-471"> + + + + + + + + + + - + gradientTransform="translate(-5.8907179,205.15612)" /> + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1,0,0,0.60717495,0,6.6355278)" + r="3.1054714" + fy="16.891813" + fx="29.111721" + cy="16.891813" + cx="29.111721" + id="radialGradient3892" + xlink:href="#linearGradient3886" + inkscape:collect="always" /> + + + + - - - - - - - - - - - - + gradientTransform="translate(-183.1468,-158.28118)" /> + id="linearGradient3942"> + + + + gradientTransform="matrix(1,0,0,1.0000234,0,-0.00345228)" + cx="237.35278" + cy="147.22479" + fx="237.35278" + fy="147.22479" + r="107.16857" /> + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + + gradientTransform="matrix(1,0,0,1.0000234,0,-0.00611206)" + cx="83.637177" + cy="260.86032" + fx="83.637177" + fy="260.86032" + r="107.16857" /> + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,52.136611,147.31246)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + + gradientTransform="matrix(1,0,0,1.0000234,0,-0.00345228)" + cx="237.35278" + cy="147.22479" + fx="237.35278" + fy="147.22479" + r="107.16857" /> + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + - - - - + + + + + + gradientTransform="matrix(0.43641683,0,0,0.43645606,205.85223,33.676924)" + cx="72.191498" + cy="260.15875" + fx="72.191498" + fy="260.15875" + r="149.18433" /> + + + + + + + + + + + + + + + + + + + + + + - - - - - - + id="linearGradient3133-9"> + + + @@ -989,36 +920,50 @@ inkscape:groupmode="layer" inkscape:label="Livello 1"> + id="g6138" + transform="translate(3.5529905,1004.1857)"> - - - + transform="matrix(3.2000002,0,0,3.2000002,101.31818,-39.364891)" + id="g6116"> + + + + + + + + + + From b7f95cd271b522f28d4dcf86799648ecd43e785f Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 24 Mar 2013 10:19:46 +0100 Subject: [PATCH 0126/1537] Random item (dice). Container.svg needs to be scraped, I'm afraid. --- .../referenceable record type/container.svg | 2770 +++++++++-------- .../referenceable record type/potion.svg | 107 +- .../referenceable record type/random item.svg | 1462 +++++++++ 3 files changed, 3045 insertions(+), 1294 deletions(-) create mode 100644 files/opencs/scalable/referenceable record type/random item.svg diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg index 6c49737083..8c9465b668 100644 --- a/files/opencs/scalable/referenceable record type/container.svg +++ b/files/opencs/scalable/referenceable record type/container.svg @@ -23,11 +23,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="5.6568545" - inkscape:cx="-6.640249" - inkscape:cy="16.907775" + inkscape:zoom="11.313709" + inkscape:cx="13.572484" + inkscape:cy="13.658831" inkscape:document-units="px" - inkscape:current-layer="g8044" + inkscape:current-layer="g3302" showgrid="true" showguides="true" inkscape:guide-bbox="true" @@ -51,1553 +51,1721 @@ inkscape:snap-nodes="true" inkscape:snap-midpoints="false"> + id="grid3225" + type="xygrid" /> + id="guide5067" /> + id="guide5069" /> + id="guide5071" /> + id="guide5073" /> + id="linearGradient4932"> + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#000e50;stop-opacity:0;" /> + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="linearGradient4853"> + style="stop-color:#eeeeee;stop-opacity:1;" /> + style="stop-color:#e1fbfa;stop-opacity:1;" /> + id="linearGradient4843"> + style="stop-color:#dcfaf9;stop-opacity:1;" /> + + style="stop-color:#dcfaf9;stop-opacity:1;" /> + id="linearGradient4817"> + style="stop-color:#caf8f6;stop-opacity:1;" /> + + style="stop-color:#caf8f6;stop-opacity:1;" /> + id="linearGradient4801"> + style="stop-color:#c8c8c8;stop-opacity:1;" /> + id="linearGradient4729"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="stop5027" /> + + id="stop5029" /> + + + + + + + + + + + + + + + + + + + + + + + + + style="stop-color:#000000;stop-opacity:0;" /> + style="stop-color:#000000;stop-opacity:1;" /> + id="linearGradient3882" + inkscape:collect="always"> + style="stop-color:#000000;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:0;" /> + style="stop-color:#000000;stop-opacity:0.784" /> + style="stop-color:#000000;stop-opacity:0;" /> + style="stop-color:#ffffff;stop-opacity:0.78431374;" /> + style="stop-color:#b4b4b4;stop-opacity:0.72549021;" /> + style="stop-color:#5a0048;stop-opacity:1;" /> + style="stop-color:#960078;stop-opacity:1;" /> + style="stop-color:#caf8f6;stop-opacity:0.39215687;" /> + id="stop3861" /> + style="stop-color:#caf8f6;stop-opacity:0.39215687;" /> + style="stop-color:#aa0088;stop-opacity:1;" /> + style="stop-color:#fa00c8;stop-opacity:1;" /> + style="stop-color:#ffffff;stop-opacity:0.78431374;" /> + style="stop-color:#caf8f6;stop-opacity:0;" /> + id="linearGradient5958" + inkscape:collect="always"> + style="stop-color:#caf8f6;stop-opacity:1;" /> + style="stop-color:#caf8f6;stop-opacity:0;" /> + style="stop-color:#c84900;stop-opacity:1;" /> + style="stop-color:#c84900;stop-opacity:0.19607843;" /> + id="stop6817" /> + style="stop-color:#3c3c3c;stop-opacity:0.58823532;" /> + id="stop6819" /> + id="stop4024" /> + id="stop4026" /> + id="stop3725" /> + id="stop3727" /> + id="stop3717" /> + id="stop3719" /> + id="stop3709" /> + id="stop3711" /> - + - - - - - - - - - - - - - + inkscape:vp_z="1 : 0.5 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_x="0 : 0.5 : 1" + sodipodi:type="inkscape:persp3d" /> + gradientTransform="translate(0.2341189,5.74082)" /> + + + + + + + + + + + + + + style="stop-color:#1e1e1e;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:0;" /> + id="radialGradient5639" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.23290796,0.98292589,-1.5211573,0.36044393,244.44953,1091.8596)" + cx="-171.01654" + cy="123.88583" + fx="-171.01654" + fy="123.88583" + r="29.000444" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + style="stop-color:#b3bbad;stop-opacity:1;" /> + id="radialGradient5641" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,227.36718,1219.3395)" + cx="-182.4375" + cy="116.19179" + fx="-182.4375" + fy="116.19179" + r="28.421875" /> + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:1;" /> - + xlink:href="#linearGradient3715-2" + id="radialGradient6812" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,240.54684,45.0811)" + cx="-172.875" + cy="119.59179" + fx="-172.875" + fy="119.59179" + r="29.000444" /> + + + + + + - - - - - + + y1="941.44623" + x1="63.765881" + gradientTransform="matrix(-0.28231332,0,0,0.28231332,64.982195,664.15172)" + gradientUnits="userSpaceOnUse" + id="linearGradient3321" + xlink:href="#linearGradient3715-6" + inkscape:collect="always" /> - + id="linearGradient6823-6" + x1="27.183681" + y1="39.630547" + x2="26.643335" + y2="37.613949" + gradientUnits="userSpaceOnUse" + gradientTransform="translate(-82.281067,1085.8147)" /> + id="stop6817-4" /> + style="stop-color:#3c3c3c;stop-opacity:0.58823532;" /> + id="stop6819-5" /> + id="radialGradient5639-0" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.0541003,0.65674043,-0.42405323,0.68062603,158.26577,1130.8958)" + cx="-172.875" + cy="119.59179" + fx="-172.875" + fy="119.59179" + r="29.000444" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + style="stop-color:#b3bbad;stop-opacity:1;" /> + id="radialGradient5641-1" + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(0.30667246,1.5835715,-1.396495,0.27044345,218.94267,1272.3725)" + cx="-182.4375" + cy="116.19179" + fx="-182.4375" + fy="116.19179" + r="28.421875" /> + style="stop-color:#000e50;stop-opacity:1;" /> + style="stop-color:#000000;stop-opacity:1;" /> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="linearGradient5973" + xlink:href="#linearGradient5922" + inkscape:collect="always" /> + fx="-97.089668" + cy="-33.913769" + cx="-97.089668" + id="radialGradient3843" + xlink:href="#linearGradient3837" + inkscape:collect="always" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + style="stop-color:#d07200;stop-opacity:1;" /> + style="stop-color:#603500;stop-opacity:1;" /> + style="stop-color:#ffffff;stop-opacity:1;" /> + style="stop-color:#cccccc;stop-opacity:0;" /> + style="stop-color:#000000;stop-opacity:1" /> + id="stop4721" /> + style="stop-color:#000000;stop-opacity:1;" /> + style="stop-color:#969696;stop-opacity:1;" /> + style="stop-color:#cccccc;stop-opacity:1;" /> + style="stop-color:#fa00c8;stop-opacity:1;" /> + style="stop-color:#aa0088;stop-opacity:1;" /> - + - - - - - - + y1="1154.9745" + x2="127.51315" + y2="1151.9221" + gradientUnits="userSpaceOnUse" /> - - + + + + + + + + + id="linearGradient6042" + gradientUnits="userSpaceOnUse" + x1="-2256.6802" + y1="1067.036" + x2="37.487514" + y2="2532.4438" + gradientTransform="translate(-1.6900304,-354.84909)" /> + id="stop6036" /> + id="stop6038" /> - + - + - + - + - + + id="linearGradient5095" + x1="5.8733373" + y1="28.879158" + x2="15.974848" + y2="24.861507" + gradientUnits="userSpaceOnUse" /> + id="linearGradient5105" + x1="44.388447" + y1="29.089437" + x2="34.262527" + y2="24.798422" + gradientUnits="userSpaceOnUse" /> + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + inkscape:collect="always" /> + y2="68.443649" + x2="148.13901" + y1="101.13522" + x1="135.41849" + id="linearGradient4807" + xlink:href="#linearGradient4801" + inkscape:collect="always" /> + + + + + + + + + + + + + @@ -1612,62 +1780,120 @@ + id="layer1" + transform="translate(0,-1004.3622)"> + id="g8044" + transform="matrix(0.29626046,0,0,0.29626046,-45.835699,695.27639)"> - - - - - - - + transform="translate(99.497853,-21.084127)" /> + transform="translate(156.56239,-59.761743)" /> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg index 612f45aa42..552c14f19f 100644 --- a/files/opencs/scalable/referenceable record type/potion.svg +++ b/files/opencs/scalable/referenceable record type/potion.svg @@ -23,9 +23,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="7.2407734" - inkscape:cx="3.6117613" - inkscape:cy="14.120537" + inkscape:zoom="5.12" + inkscape:cx="-13.774317" + inkscape:cy="16.062941" inkscape:document-units="px" inkscape:current-layer="g3910" showgrid="true" @@ -41,7 +41,7 @@ inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:snap-bbox-edge-midpoints="true" - inkscape:snap-bbox-midpoints="true" + inkscape:snap-bbox-midpoints="false" inkscape:object-paths="true" inkscape:snap-intersection-paths="false" inkscape:object-nodes="false" @@ -55,6 +55,21 @@ + + + + + + gradientUnits="userSpaceOnUse" + gradientTransform="matrix(1.2031694,0,0,1.0551213,-87.506267,947.79452)" /> + + + + + @@ -1067,26 +1130,26 @@ d="m -133.13494,-22.158251 c 0,2.440777 -8.84205,4.419418 -19.74928,4.419418 -10.90722,0 -19.74927,-1.978641 -19.74927,-4.419418 0,-2.440777 8.84205,-4.419417 19.74927,-4.419417 10.90723,0 19.74928,1.97864 19.74928,4.419417 z" transform="matrix(0.33492065,0,0,0.3605492,-27.223425,956.85737)" /> + style="opacity:0.75;fill:url(#linearGradient3148);fill-opacity:1;stroke:#7d7d7d;stroke-width:0.43104154;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" + d="m -84.982974,948.64215 c -0.64997,0.0595 -1.165571,0.65963 -1.165571,1.38485 l 0,2.6378 c 0,0.7229 0.518091,1.32155 1.165571,1.38485 l 0,0.46162 c 0.544843,-0.74781 3.244284,-1.3189 6.504634,-1.3189 3.36081,0 6.119682,0.60297 6.542234,1.38484 l 0.0752,0 0,-0.52756 c 0.64747,-0.063 1.16557,-0.66195 1.16557,-1.38485 l 0,-2.6378 c 0,-0.73861 -0.535775,-1.34418 -1.203169,-1.38485 0.04468,0.0748 0.0752,0.15305 0.0752,0.23081 0,0.88002 -2.964378,1.58268 -6.617432,1.58268 -3.653054,0 -6.617431,-0.70266 -6.617431,-1.58268 0,-0.076 0.03245,-0.15762 0.0752,-0.23081 z" + id="path3920" + inkscape:connector-curvature="0" /> + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + From 4208d52b1ac67ae40f43d190c8a7aadeff3c3f06 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Mar 2013 14:51:48 +0100 Subject: [PATCH 0127/1537] added use value columns to skills --- apps/opencs/model/world/columns.hpp | 32 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 43aad889d9..1836dbe7f4 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H +#include + #include "columnbase.hpp" namespace CSMWorld @@ -227,6 +229,36 @@ namespace CSMWorld return true; } }; + + template + struct UseValueColumn : public Column + { + int mIndex; + + UseValueColumn (int index) + : Column ("Use value #" + boost::lexical_cast (index), + ColumnBase::Display_Float), mIndex (index) + {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mUseValue[mIndex]; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mUseValue[mIndex] = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index de85beed45..1b65fecc03 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -39,7 +39,8 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); mSkills.addColumn (new SpecialisationColumn); - + for (int i=0; i<4; ++i) + mSkills.addColumn (new UseValueColumn (i)); mSkills.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From 114f99ddbf0b0e6fb99c116e0622ab9da7dbd47d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 24 Mar 2013 15:10:03 +0100 Subject: [PATCH 0128/1537] add skill records when creating a new base file --- apps/opencs/model/doc/document.cpp | 10 ++++++++++ apps/opencs/model/world/data.cpp | 10 ++++++++++ apps/opencs/model/world/data.hpp | 4 ++++ components/esm/loadskil.cpp | 32 ++++++++++++++++++------------ components/esm/loadskil.hpp | 2 ++ 5 files changed, 45 insertions(+), 13 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 47cf1f6642..deafe8eb84 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -198,6 +198,16 @@ void CSMDoc::Document::createBase() } /// \todo add GMSTs + + for (int i=0; i<27; ++i) + { + ESM::Skill record; + record.mIndex = i; + record.mId = ESM::Skill::getIndexToId (record.mIndex); + record.blank(); + + getData().getSkills().add (record); + } } CSMDoc::Document::Document (const std::vector& files, bool new_) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 1b65fecc03..bc78cb46be 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -74,6 +74,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getGmsts() return mGmsts; } +const CSMWorld::IdCollection& CSMWorld::Data::getSkills() const +{ + return mSkills; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSkills() +{ + return mSkills; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index dc9aee0618..ac953dbece 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -46,6 +46,10 @@ namespace CSMWorld IdCollection& getGmsts(); + const IdCollection& getSkills() const; + + IdCollection& getSkills(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index ac9fc27897..b9d588eef4 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -103,19 +103,7 @@ void Skill::load(ESMReader &esm) // create an ID from the index and the name (only used in the editor and likely to change in the // future) - std::ostringstream stream; - - stream << "#"; - - if (mIndex<10) - stream << "0"; - - stream << mIndex; - - if (mIndex>=0 && mIndex=0 && index Date: Sun, 24 Mar 2013 15:50:29 +0100 Subject: [PATCH 0129/1537] added attribute column to skills --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 26 ++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/doc/viewmanager.cpp | 9 +++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index a098fcb7e5..b5863f8e4e 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -32,7 +32,8 @@ namespace CSMWorld Display_Var, Display_GmstVarType, Display_GlobalVarType, - Display_Specialisation + Display_Specialisation, + Display_Attribute }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 1836dbe7f4..7764f58709 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -259,6 +259,32 @@ namespace CSMWorld return true; } }; + + template + struct AttributeColumn : public Column + { + AttributeColumn() : Column ("Attribute", ColumnBase::Display_Attribute) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mAttribute; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mAttribute = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index bc78cb46be..4b10a66836 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -38,6 +38,7 @@ CSMWorld::Data::Data() mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new AttributeColumn); mSkills.addColumn (new SpecialisationColumn); for (int i=0; i<4; ++i) mSkills.addColumn (new UseValueColumn (i)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index f59be3d997..bc87728945 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -43,6 +43,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) "Combat", "Magic", "Stealth", 0 }; + static const char *sAttributes[] = + { + "Strength", "Intelligence", "Willpower", "Agility", "Speed", "Endurance", "Personality", + "Luck", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -53,6 +59,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_Specialisation, new CSVWorld::EnumDelegateFactory (sSpecialisations)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, + new CSVWorld::EnumDelegateFactory (sAttributes)); } CSVDoc::ViewManager::~ViewManager() From 7450554ef105bacd7e8ccc2e62d713b895b33a67 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:04:41 +0100 Subject: [PATCH 0130/1537] fixed a broken UniversalId constructor --- apps/opencs/model/world/universalid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6fce376bea..57c276a6d3 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -45,7 +45,7 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string::size_type index = universalId.find (':'); - if (index==std::string::npos) + if (index!=std::string::npos) { std::string type = universalId.substr (0, index); From 739e7e7298e10c401ff18aba0637fb4879150164 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:06:40 +0100 Subject: [PATCH 0131/1537] improved record access from ID collection --- apps/opencs/model/world/idcollection.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 9b69dfb889..3bf53349e6 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -74,6 +74,8 @@ namespace CSMWorld virtual const RecordBase& getRecord (const std::string& id) const = 0; + virtual const RecordBase& getRecord (int index) const = 0; + virtual void load (ESM::ESMReader& reader, bool base) = 0; }; @@ -139,7 +141,9 @@ namespace CSMWorld /// /// \attention Throw san exception, if the type of \a record does not match. - virtual const RecordBase& getRecord (const std::string& id) const; + virtual const Record& getRecord (const std::string& id) const; + + virtual const Record& getRecord (int index) const; virtual void load (ESM::ESMReader& reader, bool base); @@ -373,11 +377,18 @@ namespace CSMWorld } template - const RecordBase& IdCollection::getRecord (const std::string& id) const + const Record& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } + + template + const Record& IdCollection::getRecord (int index) const + { + return mRecords.at (index); + } + } #endif From dc67ddf39b43c41e3109b71a03122906214d1d68 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:07:04 +0100 Subject: [PATCH 0132/1537] added verifier stage for skill records --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/skillcheck.cpp | 37 ++++++++++++++++++++++++++ apps/opencs/model/tools/skillcheck.hpp | 29 ++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/skillcheck.cpp create mode 100644 apps/opencs/model/tools/skillcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 488e3c65f5..a305d90d93 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid + stage verifier mandatoryid skillcheck ) diff --git a/apps/opencs/model/tools/skillcheck.cpp b/apps/opencs/model/tools/skillcheck.cpp new file mode 100644 index 0000000000..897aeab473 --- /dev/null +++ b/apps/opencs/model/tools/skillcheck.cpp @@ -0,0 +1,37 @@ + +#include "skillcheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SkillCheckStage::SkillCheckStage (const CSMWorld::IdCollection& skills) +: mSkills (skills) +{} + +int CSMTools::SkillCheckStage::setup() +{ + return mSkills.getSize(); +} + +void CSMTools::SkillCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Skill& skill = mSkills.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Skill, skill.mId); + + for (int i=0; i<4; ++i) + if (skill.mData.mUseValue[i]<0) + { + std::ostringstream stream; + + stream << id.toString() << "|Use value #" << i << " of " << skill.mId << " is negative"; + + messages.push_back (stream.str()); + } + + if (skill.mDescription.empty()) + messages.push_back (id.toString() + "|" + skill.mId + " has an empty description"); +} \ No newline at end of file diff --git a/apps/opencs/model/tools/skillcheck.hpp b/apps/opencs/model/tools/skillcheck.hpp new file mode 100644 index 0000000000..30a3f01cad --- /dev/null +++ b/apps/opencs/model/tools/skillcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SKILLCHECK_H +#define CSM_TOOLS_SKILLCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that skill records are internally consistent + class SkillCheckStage : public Stage + { + const CSMWorld::IdCollection& mSkills; + + public: + + SkillCheckStage (const CSMWorld::IdCollection& skills); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 8dd1c0fe6f..33cc3cc61b 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -12,6 +12,7 @@ #include "reportmodel.hpp" #include "mandatoryid.hpp" +#include "skillcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -51,6 +52,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(), CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); + + mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); } return mVerifier; From 6c76e97bbc65e8ae101dc6fe7bf427e30a5974fe Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:53:02 +0100 Subject: [PATCH 0133/1537] fixed day count in rest dialogue --- apps/openmw/mwgui/waitdialog.cpp | 20 ++++++++++---------- apps/openmw/mwworld/globals.cpp | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 6e914a669b..df8a52456c 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -132,7 +132,7 @@ namespace MWGui case 11: month = "#{sMonthEveningstar}"; break; - default: + default: break; } int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); @@ -142,7 +142,7 @@ namespace MWGui std::string dateTimeText = boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()) + " " - + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay ()+1) + + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay()) + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); mDateTimeText->setCaptionWithReplacing (dateTimeText); @@ -156,13 +156,13 @@ namespace MWGui MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats stats = MWWorld::Class::get(player).getCreatureStats(player); const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - + float hourlyHealthDelta = stats.getAttribute(ESM::Attribute::Endurance).getModified() * 0.1; - + bool stunted = (stats.getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::StuntedMagicka)).mMagnitude > 0); float fRestMagicMult = store.get().find("fRestMagicMult")->getFloat(); float hourlyMagickaDelta = fRestMagicMult * stats.getAttribute(ESM::Attribute::Intelligence).getModified(); - + // this massive duplication is why it has to be put into helper functions instead float fFatigueReturnBase = store.get().find("fFatigueReturnBase")->getFloat(); float fFatigueReturnMult = store.get().find("fFatigueReturnMult")->getFloat(); @@ -174,7 +174,7 @@ namespace MWGui normalizedEncumbrance = 1; float hourlyFatigueDelta = fFatigueReturnBase + fFatigueReturnMult * (1 - normalizedEncumbrance); hourlyFatigueDelta *= 3600 * fEndFatigueMult * stats.getAttribute(ESM::Attribute::Endurance).getModified(); - + float healthHours = hourlyHealthDelta >= 0.0 ? (stats.getHealth().getBase() - stats.getHealth().getCurrent()) / hourlyHealthDelta : 1.0f; @@ -185,9 +185,9 @@ namespace MWGui float fatigueHours = hourlyFatigueDelta >= 0.0 ? (stats.getFatigue().getBase() - stats.getFatigue().getCurrent()) / hourlyFatigueDelta : 1.0f; - + int autoHours = int(std::ceil( std::max(std::max(healthHours, magickaHours), std::max(fatigueHours, 1.0f)) )); // this should use a variadic max if possible - + startWaiting(autoHours); } @@ -201,11 +201,11 @@ namespace MWGui MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); setVisible(false); mProgressBar.setVisible (true); - + mWaiting = true; mCurHour = 0; mHours = hoursToWait; - + mRemainingTime = 0.05; mProgressBar.setProgress (0, mHours); } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 9e57910ee0..72bebc0498 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -79,7 +79,7 @@ namespace MWWorld { // vanilla Morrowind does not define dayspassed. Data value; - value.mLong = 0; + value.mLong = 1; // but the addons start counting at 1 :( mVariables.insert (std::make_pair ("dayspassed", std::make_pair ('l', value))); } From f39f6946389525699faefdb8e5aedba30040bee5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 11:59:25 +0100 Subject: [PATCH 0134/1537] various global variable fixes in editor --- apps/opencs/model/doc/document.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index deafe8eb84..d1462d6a3f 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -150,6 +150,10 @@ void CSMDoc::Document::addOptionalGlobals() ESM::Global global; global.mId = sGlobals[i]; global.mValue.setType (ESM::VT_Long); + + if (i==0) + global.mValue.setInteger (1); // dayspassed starts counting at 1 + addOptionalGlobal (global); } } @@ -189,9 +193,9 @@ void CSMDoc::Document::createBase() record.mId = sGlobals[i]; - record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int); + record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Long); - if (i==0) + if (i==0 || i==1) record.mValue.setInteger (1); getData().getGlobals().add (record); From f2969e7143d9f050bc2745c54de3a65850db5189 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 12:56:52 +0100 Subject: [PATCH 0135/1537] fixed access to records flagged as deleted --- apps/opencs/model/world/record.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/opencs/model/world/record.hpp b/apps/opencs/model/world/record.hpp index e442d0a391..c8f728e7d1 100644 --- a/apps/opencs/model/world/record.hpp +++ b/apps/opencs/model/world/record.hpp @@ -62,7 +62,7 @@ namespace CSMWorld if (mState==State_Erased) throw std::logic_error ("attempt to access a deleted record"); - return mState==State_BaseOnly ? mBase : mModified; + return mState==State_BaseOnly || mState==State_Deleted ? mBase : mModified; } template From c7275965b8c8e419eec920db231f59270bdf1059 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 13:22:06 +0100 Subject: [PATCH 0136/1537] added basic class record table --- apps/opencs/model/world/data.cpp | 7 +++++++ apps/opencs/model/world/data.hpp | 2 ++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 7 +++++-- components/esm/loadclas.cpp | 14 ++++++++++++++ components/esm/loadclas.hpp | 4 ++++ 9 files changed, 48 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 4b10a66836..2b635d9abe 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -44,9 +44,15 @@ CSMWorld::Data::Data() mSkills.addColumn (new UseValueColumn (i)); mSkills.addColumn (new DescriptionColumn); + mClasses.addColumn (new StringIdColumn); + mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new SpecialisationColumn); + mClasses.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); + addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); } CSMWorld::Data::~Data() @@ -122,6 +128,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_GLOB: mGlobals.load (reader, base); break; case ESM::REC_GMST: mGmsts.load (reader, base); break; case ESM::REC_SKIL: mSkills.load (reader, base); break; + case ESM::REC_CLAS: mClasses.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index ac953dbece..7baf03259e 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -22,6 +23,7 @@ namespace CSMWorld IdCollection mGlobals; IdCollection mGmsts; IdCollection mSkills; + IdCollection mClasses; std::vector mModels; std::map mModelIndex; diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 57c276a6d3..a85b30c2a8 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -20,6 +20,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -29,6 +30,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Global, "Global Variable" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a412cb6b1e..4c4d95654b 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -39,7 +39,9 @@ namespace CSMWorld Type_Gmsts, Type_Gmst, Type_Skills, - Type_Skill + Type_Skill, + Type_Classes, + Type_Class }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 267ddf26cc..2ef66593f7 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -90,6 +90,10 @@ void CSVDoc::View::setupWorldMenu() connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView())); world->addAction (skills); + QAction *classes = new QAction (tr ("Classes"), this); + connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); + world->addAction (classes); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -253,6 +257,11 @@ void CSVDoc::View::addSkillsSubView() addSubView (CSMWorld::UniversalId::Type_Skills); } +void CSVDoc::View::addClassesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Classes); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4c5aa40784..bc8e8fc26d 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -117,6 +117,8 @@ namespace CSVDoc void addGmstsSubView(); void addSkillsSubView(); + + void addClassesSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index bdff0017b4..5d715ea21e 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -17,6 +17,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Skills, new CSVDoc::SubViewFactoryWithCreateFlag (false)); - manager.add (CSMWorld::UniversalId::Type_Global, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Classes, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); + +// manager.add (CSMWorld::UniversalId::Type_Global, +// new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index a626689504..d9f367fd63 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -35,4 +35,18 @@ void Class::save(ESMWriter &esm) esm.writeHNOString("DESC", mDescription); } + void Class::blank() + { + mName.clear(); + mDescription.clear(); + + mData.mAttribute[0] = mData.mAttribute[1] = 0; + mData.mSpecialization = 0; + mData.mIsPlayable = 0; + mData.mCalc = 0; + + for (int i=0; i<5; ++i) + for (int i2=0; i2<2; ++i2) + mData.mSkills[i][i2] = 0; + } } diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index 264e342e63..ac596af32c 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -65,6 +65,10 @@ struct Class void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). + }; } #endif From 65cda580db62ccba881a6518d880c5027c38824a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 25 Mar 2013 14:31:46 +0100 Subject: [PATCH 0137/1537] added attributes to class table --- apps/opencs/model/world/columns.hpp | 53 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++ 2 files changed, 56 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 7764f58709..b41e98f409 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -285,6 +285,59 @@ namespace CSMWorld } }; + template + struct NameColumn : public Column + { + NameColumn() : Column ("Name", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mName.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mName = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct AttributesColumn : public Column + { + int mIndex; + + AttributesColumn (int index) + : Column ("Attribute #" + boost::lexical_cast (index), + ColumnBase::Display_Attribute), mIndex (index) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mAttribute[mIndex]; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mAttribute[mIndex] = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 2b635d9abe..b0a8b95a6f 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -46,6 +46,9 @@ CSMWorld::Data::Data() mClasses.addColumn (new StringIdColumn); mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new NameColumn); + mClasses.addColumn (new AttributesColumn (0)); + mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); mClasses.addColumn (new DescriptionColumn); From 4be0c6b70867f3514c088c522f687d45da855dd6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Mar 2013 17:32:01 +0100 Subject: [PATCH 0138/1537] Fix topics not being selectable for creatures --- apps/openmw/mwgui/dialogue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 9a7e51874f..d045725fb1 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -230,14 +230,14 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) { if (!mEnabled) return; - int separatorPos = mTopicsList->getItemCount(); + int separatorPos = 0; for (unsigned int i=0; igetItemCount(); ++i) { if (mTopicsList->getItemNameAt(i) == "") separatorPos = i; } - if (id > separatorPos) + if (id >= separatorPos) MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); else { From 6a2b87e14a5ed565caf4f7e208c9c398d8a6611a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 25 Mar 2013 17:37:59 +0100 Subject: [PATCH 0139/1537] Fix dialogue response coloring for creatures --- apps/openmw/mwgui/dialogue.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index d045725fb1..bfbd60b07d 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -389,10 +389,17 @@ std::string DialogueWindow::parseText(const std::string& text) std::vector topics; + bool hasSeparator = false; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + hasSeparator = true; + } + for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached) + if (separatorReached || !hasSeparator) topics.push_back(keyWord); else if (keyWord == "") separatorReached = true; From 37a1fb6b7c82a5477c17faf6ec8538e0e2a03676 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 26 Mar 2013 09:41:26 +0100 Subject: [PATCH 0140/1537] Adding ingredient.svg icon. I need to work on random-item and scrap container icon. --- .../referenceable record type/ingredient.svg | 1112 ++++++++++ .../referenceable record type/light.svg | 1513 +++++++++++++ .../referenceable record type/random-item.svg | 1462 +++++++++++++ .../scalable/referenceable-record/.directory | 5 + .../referenceable-record/activator.svg | 1088 ++++++++++ .../referenceable-record/apparatus.svg | 1058 +++++++++ .../scalable/referenceable-record/book.svg | 692 ++++++ .../referenceable-record/container.svg | 1899 +++++++++++++++++ .../referenceable-record/ingredient.svg | 1112 ++++++++++ .../scalable/referenceable-record/light.svg | 1513 +++++++++++++ .../scalable/referenceable-record/potion.svg | 1161 ++++++++++ .../referenceable-record/random-item.svg | 1462 +++++++++++++ .../scalable/referenceable-record/repair.svg | 1280 +++++++++++ .../scalable/referenceable-record/static.svg | 1141 ++++++++++ .../scalable/referenceable-record/weapon.svg | 1206 +++++++++++ 15 files changed, 17704 insertions(+) create mode 100644 files/opencs/scalable/referenceable record type/ingredient.svg create mode 100644 files/opencs/scalable/referenceable record type/light.svg create mode 100644 files/opencs/scalable/referenceable record type/random-item.svg create mode 100644 files/opencs/scalable/referenceable-record/.directory create mode 100644 files/opencs/scalable/referenceable-record/activator.svg create mode 100644 files/opencs/scalable/referenceable-record/apparatus.svg create mode 100644 files/opencs/scalable/referenceable-record/book.svg create mode 100644 files/opencs/scalable/referenceable-record/container.svg create mode 100644 files/opencs/scalable/referenceable-record/ingredient.svg create mode 100644 files/opencs/scalable/referenceable-record/light.svg create mode 100644 files/opencs/scalable/referenceable-record/potion.svg create mode 100644 files/opencs/scalable/referenceable-record/random-item.svg create mode 100644 files/opencs/scalable/referenceable-record/repair.svg create mode 100644 files/opencs/scalable/referenceable-record/static.svg create mode 100644 files/opencs/scalable/referenceable-record/weapon.svg diff --git a/files/opencs/scalable/referenceable record type/ingredient.svg b/files/opencs/scalable/referenceable record type/ingredient.svg new file mode 100644 index 0000000000..a77a9c8ee7 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/ingredient.svg @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/light.svg b/files/opencs/scalable/referenceable record type/light.svg new file mode 100644 index 0000000000..f8f5066365 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/light.svg @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable record type/random-item.svg b/files/opencs/scalable/referenceable record type/random-item.svg new file mode 100644 index 0000000000..0c132ce958 --- /dev/null +++ b/files/opencs/scalable/referenceable record type/random-item.svg @@ -0,0 +1,1462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory new file mode 100644 index 0000000000..e2d80ed58c --- /dev/null +++ b/files/opencs/scalable/referenceable-record/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg new file mode 100644 index 0000000000..0c6db59a7d --- /dev/null +++ b/files/opencs/scalable/referenceable-record/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/apparatus.svg b/files/opencs/scalable/referenceable-record/apparatus.svg new file mode 100644 index 0000000000..37cef0e890 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/book.svg b/files/opencs/scalable/referenceable-record/book.svg new file mode 100644 index 0000000000..8c041a9e7a --- /dev/null +++ b/files/opencs/scalable/referenceable-record/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/container.svg b/files/opencs/scalable/referenceable-record/container.svg new file mode 100644 index 0000000000..8c9465b668 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/container.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/ingredient.svg b/files/opencs/scalable/referenceable-record/ingredient.svg new file mode 100644 index 0000000000..a77a9c8ee7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/ingredient.svg @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/light.svg b/files/opencs/scalable/referenceable-record/light.svg new file mode 100644 index 0000000000..f8f5066365 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/light.svg @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/potion.svg b/files/opencs/scalable/referenceable-record/potion.svg new file mode 100644 index 0000000000..552c14f19f --- /dev/null +++ b/files/opencs/scalable/referenceable-record/potion.svg @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg new file mode 100644 index 0000000000..0c132ce958 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/random-item.svg @@ -0,0 +1,1462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/repair.svg b/files/opencs/scalable/referenceable-record/repair.svg new file mode 100644 index 0000000000..b1a23956e3 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/repair.svg @@ -0,0 +1,1280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/static.svg b/files/opencs/scalable/referenceable-record/static.svg new file mode 100644 index 0000000000..a6f29370f0 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/weapon.svg b/files/opencs/scalable/referenceable-record/weapon.svg new file mode 100644 index 0000000000..2e832fff76 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/weapon.svg @@ -0,0 +1,1206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + From ea3b14f2d25d3174ad57d7fa7d4d7acc23e7d0ef Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Mar 2013 09:43:13 +0100 Subject: [PATCH 0141/1537] added skill columns to class --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/columns.hpp | 46 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 4 +++ components/esm/loadskil.cpp | 7 +++-- components/esm/loadskil.hpp | 2 +- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index d1462d6a3f..acca877f0a 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -207,7 +207,7 @@ void CSMDoc::Document::createBase() { ESM::Skill record; record.mIndex = i; - record.mId = ESM::Skill::getIndexToId (record.mIndex); + record.mId = ESM::Skill::indexToId (record.mIndex); record.blank(); getData().getSkills().add (record); diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b41e98f409..902d7d86fc 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -1,6 +1,8 @@ #ifndef CSM_WOLRD_COLUMNS_H #define CSM_WOLRD_COLUMNS_H +#include + #include #include "columnbase.hpp" @@ -338,6 +340,50 @@ namespace CSMWorld return true; } }; + + template + struct SkillsColumn : public Column + { + int mIndex; + bool mMajor; + + SkillsColumn (int index, bool major) + : Column ((major ? "Major Skill #" : "Minor Skill #")+ + boost::lexical_cast (index), ColumnBase::Display_String), + mIndex (index), mMajor (major) + {} + + virtual QVariant get (const Record& record) const + { + int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0]; + + return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + std::istringstream stream (data.toString().toUtf8().constData()); + + int index = -1; + char c; + + stream >> c >> index; + + if (index!=-1) + { + ESXRecordT record2 = record.get(); + + record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index; + + record.setModified (record2); + } + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b0a8b95a6f..917be26325 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -50,6 +50,10 @@ CSMWorld::Data::Data() mClasses.addColumn (new AttributesColumn (0)); mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); + for (int i=0; i<5; ++i) + mClasses.addColumn (new SkillsColumn (i, true)); + for (int i=0; i<5; ++i) + mClasses.addColumn (new SkillsColumn (i, false)); mClasses.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b9d588eef4..b7259db94e 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -2,6 +2,8 @@ #include +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -103,8 +105,9 @@ void Skill::load(ESMReader &esm) // create an ID from the index and the name (only used in the editor and likely to change in the // future) - mId = getIndexToId (mIndex); + mId = indexToId (mIndex); } + void Skill::save(ESMWriter &esm) { esm.writeHNT("INDX", mIndex); @@ -120,7 +123,7 @@ void Skill::save(ESMWriter &esm) mDescription.clear(); } - std::string Skill::getIndexToId (int index) + std::string Skill::indexToId (int index) { std::ostringstream stream; diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 83a4d8bfd9..43f4fc45e9 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -79,7 +79,7 @@ struct Skill void blank(); ///< Set record to default state (does not touch the ID/index). - static std::string getIndexToId (int index); + static std::string indexToId (int index); }; } #endif From 82f1cee116a740e853be87a732cfbf52dac3ec1c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Mar 2013 09:51:39 +0100 Subject: [PATCH 0142/1537] added is-playable column to class --- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index b5863f8e4e..5c2ce8a676 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -33,7 +33,8 @@ namespace CSMWorld Display_GmstVarType, Display_GlobalVarType, Display_Specialisation, - Display_Attribute + Display_Attribute, + Display_Boolean }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 902d7d86fc..cbcddd972d 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -384,6 +384,31 @@ namespace CSMWorld return true; } }; + + template + struct PlayableColumn : public Column + { + PlayableColumn() : Column ("Playable", ColumnBase::Display_Boolean) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mIsPlayable!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mIsPlayable = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 917be26325..7b3e667715 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -54,6 +54,7 @@ CSMWorld::Data::Data() mClasses.addColumn (new SkillsColumn (i, true)); for (int i=0; i<5; ++i) mClasses.addColumn (new SkillsColumn (i, false)); + mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From cf0c55b37fa033ab6748ffa814a6c89bddf7c543 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Tue, 26 Mar 2013 10:28:43 +0100 Subject: [PATCH 0143/1537] New random-item. Looks a lot better. --- .../referenceable-record/random-item.svg | 1560 ++--------------- 1 file changed, 127 insertions(+), 1433 deletions(-) diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg index 0c132ce958..d051ce049f 100644 --- a/files/opencs/scalable/referenceable-record/random-item.svg +++ b/files/opencs/scalable/referenceable-record/random-item.svg @@ -1,5 +1,5 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + inkscape:version="0.48.4 r9939" + sodipodi:docname="random-item.svg"> + id="metadata14614"> image/svg+xml - + + + + id="layer1"> + transform="translate(26.2199, 33.6274)" + fill="#fa0000" + d="M6.67184 0L6.67184 3.5776L0 3.5776L10.8901 14.3726L21.7801 3.5776L15.1083 3.5776L15.1083 0Z" /> - - - - - - - - - + transform="translate(-0.222381, -0.133277)" + fill="none"> + + + + + + + + + + + + + + + + + From efe6a3ebeec495a213a75ed3c072d9d2eb1c8c95 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 26 Mar 2013 18:01:01 +0100 Subject: [PATCH 0144/1537] Fix compile error & warnings --- apps/openmw/mwmechanics/aitravel.cpp | 6 +-- apps/openmw/mwmechanics/aitravel.hpp | 60 ++++++++++++++-------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 94f6fd8928..2c5260a625 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -46,7 +46,7 @@ int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) float m = distance(grid->mPoints[0],x,y,z); int i0 = 0; - for(int i=1; imPoints.size();i++) + for(unsigned int i=1; imPoints.size();++i) { if(distance(grid->mPoints[i],x,y,z)mPoints.size();i++) + for(unsigned int i = 0;imPoints.size();++i) { PointID pID = boost::add_vertex(graph); graph[pID].mX = pathgrid->mPoints[i].mX + xCell; @@ -147,7 +147,7 @@ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCe graph[pID].mZ = pathgrid->mPoints[i].mZ; } - for(int i = 0;imEdges.size();i++) + for(unsigned int i = 0;imEdges.size();++i) { PointID u = pathgrid->mEdges[i].mV0; PointID v = pathgrid->mEdges[i].mV1; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index 3d220cb7e3..ef2359ba91 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -1,35 +1,35 @@ #ifndef GAME_MWMECHANICS_AITRAVEL_H #define GAME_MWMECHANICS_AITRAVEL_H - -#include "aipackage.hpp" -#include "components\esm\loadpgrd.hpp" -#include - -namespace MWMechanics -{ - class AiTravel : public AiPackage - { - public: - AiTravel(float x, float y, float z); - virtual AiTravel *clone() const; - - virtual bool execute (const MWWorld::Ptr& actor); - ///< \return Package completed? - - virtual int getTypeId() const; - - private: - float mX; - float mY; - float mZ; - - int cellX; - int cellY; - - bool isPathConstructed; - std::list mPath; - - }; + +#include "aipackage.hpp" +#include +#include + +namespace MWMechanics +{ + class AiTravel : public AiPackage + { + public: + AiTravel(float x, float y, float z); + virtual AiTravel *clone() const; + + virtual bool execute (const MWWorld::Ptr& actor); + ///< \return Package completed? + + virtual int getTypeId() const; + + private: + float mX; + float mY; + float mZ; + + int cellX; + int cellY; + + bool isPathConstructed; + std::list mPath; + + }; } #endif From 6f1575d42a046bff854f0a79cb834e6aaf38f4fe Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Mar 2013 17:27:43 +0100 Subject: [PATCH 0145/1537] CELL record corrections --- apps/esmtool/esmtool.cpp | 5 ++++- apps/openmw/mwclass/misc.cpp | 13 +++++++++---- apps/openmw/mwworld/containerstore.cpp | 3 ++- apps/openmw/mwworld/manualref.hpp | 5 +++-- components/esm/loadcell.cpp | 24 ++++++++++++++++-------- components/esm/loadcell.hpp | 12 +++++++++--- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/apps/esmtool/esmtool.cpp b/apps/esmtool/esmtool.cpp index 521383f3ff..d682cf88b9 100644 --- a/apps/esmtool/esmtool.cpp +++ b/apps/esmtool/esmtool.cpp @@ -227,7 +227,10 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info) std::cout << " Refnum: " << ref.mRefnum << std::endl; std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n"; - std::cout << " Uses/health: " << ref.mCharge << " NAM9: " << ref.mNam9 << std::endl; + std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; + std::cout << " Uses/health: '" << ref.mCharge << "'\n"; + std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; + std::cout << " Blocked: '" << static_cast(ref.mReferenceBlocked) << "'" << std::endl; } } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 07e41bcfa6..31ae1cfb05 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -89,7 +89,9 @@ namespace MWClass MWWorld::LiveCellRef *ref = ptr.get(); - return ref->mBase->mData.mValue; + int value = (ptr.getCellRef().mGoldValue == 1) ? ref->mBase->mData.mValue : ptr.getCellRef().mGoldValue; + + return value; } void Miscellaneous::registerSelf() @@ -151,8 +153,10 @@ namespace MWClass int count = ptr.getRefData().getCount(); bool isGold = (ref->mBase->mName == store.get().find("sGold")->getString()); - if (isGold && count == 1) - count = ref->mBase->mData.mValue; + if (isGold && ptr.getCellRef().mGoldValue != 1) + count = ptr.getCellRef().mGoldValue; + else if (isGold) + count *= ref->mBase->mData.mValue; std::string countString; if (!isGold) @@ -214,7 +218,8 @@ namespace MWClass MWWorld::LiveCellRef *ref = newRef.getPtr().get(); newPtr = MWWorld::Ptr(&cell.mMiscItems.insert(*ref), &cell); - newPtr.getRefData ().setCount(goldAmount); + newPtr.getRefData ().setCount(1); + newPtr.getCellRef().mGoldValue = goldAmount; } else { MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ac27beb44a..e5b68841b8 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -124,7 +124,8 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) { MWWorld::ManualRef ref(esmStore, "Gold_001"); - int count = (ptr.getRefData().getCount() == 1) ? gold->mBase->mData.mValue : ptr.getRefData().getCount(); + int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); + ref.getPtr().getRefData().setCount(count); for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { diff --git a/apps/openmw/mwworld/manualref.hpp b/apps/openmw/mwworld/manualref.hpp index 58395d8798..6616165fae 100644 --- a/apps/openmw/mwworld/manualref.hpp +++ b/apps/openmw/mwworld/manualref.hpp @@ -69,10 +69,11 @@ namespace MWWorld cellRef.mScale = 1; cellRef.mFactIndex = 0; cellRef.mCharge = -1; - cellRef.mNam9 = 0; + cellRef.mGoldValue = 1; + cellRef.mEnchantmentCharge = -1; cellRef.mTeleport = false; cellRef.mLockLevel = 0; - cellRef.mUnam = 0; + cellRef.mReferenceBlocked = 0; } const Ptr& getPtr() const diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 0731a8ff80..5cbf1de2b7 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -43,11 +43,14 @@ void CellRef::save(ESMWriter &esm) esm.writeHNT("INDX", mFactIndex); } + if (mEnchantmentCharge != -1) + esm.writeHNT("XCHG", mEnchantmentCharge); + if (mCharge != -1) esm.writeHNT("INTV", mCharge); - if (mNam9 != 0) { - esm.writeHNT("NAM9", mNam9); + if (mGoldValue != 1) { + esm.writeHNT("NAM9", mGoldValue); } if (mTeleport) @@ -62,8 +65,8 @@ void CellRef::save(ESMWriter &esm) esm.writeHNOCString("KNAM", mKey); esm.writeHNOCString("TNAM", mTrap); - if (mUnam != -1) { - esm.writeHNT("UNAM", mUnam); + if (mReferenceBlocked != -1) { + esm.writeHNT("UNAM", mReferenceBlocked); } if (mFltv != 0) { esm.writeHNT("FLTV", mFltv); @@ -281,10 +284,15 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mFactIndex = -2; esm.getHNOT(ref.mFactIndex, "INDX"); - ref.mNam9 = 0; + ref.mGoldValue = 1; ref.mCharge = -1; + ref.mEnchantmentCharge = -1; + + esm.getHNOT(ref.mEnchantmentCharge, "XCHG"); + esm.getHNOT(ref.mCharge, "INTV"); - esm.getHNOT(ref.mNam9, "NAM9"); + + esm.getHNOT(ref.mGoldValue, "NAM9"); // Present for doors that teleport you to another cell. if (esm.isNextSub("DODT")) @@ -302,9 +310,9 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref) ref.mKey = esm.getHNOString("KNAM"); ref.mTrap = esm.getHNOString("TNAM"); - ref.mUnam = -1; + ref.mReferenceBlocked = -1; ref.mFltv = 0; - esm.getHNOT(ref.mUnam, "UNAM"); + esm.getHNOT(ref.mReferenceBlocked, "UNAM"); esm.getHNOT(ref.mFltv, "FLTV"); esm.getHNOT(ref.mPos, "DATA", 24); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 97aa86ba0f..afc953f54c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -56,7 +56,11 @@ public: // For tools (lockpicks, probes, repair hammer) it is the remaining uses. int mCharge; - int mNam9; + // Remaining enchantment charge + float mEnchantmentCharge; + + // This is 5 for Gold_005 references, 100 for Gold_100 and so on. + int mGoldValue; // For doors - true if this door teleports to somewhere else, false // if it should open through animation. @@ -72,8 +76,10 @@ public: int mLockLevel; std::string mKey, mTrap; // Key and trap ID names, if any - // No idea - occurs ONCE in Morrowind.esm, for an activator - signed char mUnam; + // This corresponds to the "Reference Blocked" checkbox in the construction set, + // which prevents editing that reference. + // -1 is not blocked, otherwise it is blocked. + signed char mReferenceBlocked; // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. int mDeleted; From 406488d086f78006256b00416f829fefd5b9b170 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Mar 2013 17:39:49 +0100 Subject: [PATCH 0146/1537] Soulgem value should be multiplied by the trapped soul --- apps/openmw/mwclass/misc.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 31ae1cfb05..b971fa6f34 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -91,6 +91,12 @@ namespace MWClass int value = (ptr.getCellRef().mGoldValue == 1) ? ref->mBase->mData.mValue : ptr.getCellRef().mGoldValue; + if (ptr.getCellRef().mSoul != "") + { + const ESM::Creature *creature = MWBase::Environment::get().getWorld()->getStore().get().find(ref->mRef.mSoul); + value *= creature->mData.mSoul; + } + return value; } @@ -178,7 +184,7 @@ namespace MWClass if (!isGold) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); - text += MWGui::ToolTips::getValueString(ref->mBase->mData.mValue, "#{sValue}"); + text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); } if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { From 564256c4e13f9ea2348de901fc73e0f0fe1d2eae Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 27 Mar 2013 18:04:15 +0100 Subject: [PATCH 0147/1537] Fix the spell icon panel being visible when it shouldn't. --- apps/openmw/mwgui/spellicons.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 16e02ebba1..206db51ed0 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -139,12 +139,13 @@ namespace MWGui } } - parent->setVisible(effects.size() != 0); - int w=2; + if (adjustSize) { int s = effects.size() * 16+4; + if (!effects.size()) + s = 0; int diff = parent->getWidth() - s; parent->setSize(s, parent->getHeight()); parent->setPosition(parent->getLeft()+diff, parent->getTop()); From 623f9c2a587d1bdeb836c0acbd2c029e651dbbde Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Wed, 27 Mar 2013 19:52:12 +0100 Subject: [PATCH 0148/1537] A new icon for misc iteams. I really hope that scales will do. --- .../referenceable-record/miscelanius.svg | 965 ++++++++++++++++++ .../referenceable-record/miscellaneous.svg | 692 +++++++++++++ 2 files changed, 1657 insertions(+) create mode 100644 files/opencs/scalable/referenceable-record/miscelanius.svg create mode 100644 files/opencs/scalable/referenceable-record/miscellaneous.svg diff --git a/files/opencs/scalable/referenceable-record/miscelanius.svg b/files/opencs/scalable/referenceable-record/miscelanius.svg new file mode 100644 index 0000000000..96522048cb --- /dev/null +++ b/files/opencs/scalable/referenceable-record/miscelanius.svg @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg new file mode 100644 index 0000000000..8c041a9e7a --- /dev/null +++ b/files/opencs/scalable/referenceable-record/miscellaneous.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + From 6643fe789cb3a909af82f245b8b743c4853bf11d Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 28 Mar 2013 17:41:00 +0100 Subject: [PATCH 0149/1537] Enchanting system --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 39 +++-- apps/openmw/mwclass/armor.cpp | 15 ++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/book.cpp | 24 ++++ apps/openmw/mwclass/book.hpp | 4 + apps/openmw/mwclass/clothing.cpp | 15 ++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 15 ++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwgui/enchantingdialog.cpp | 104 ++++++++++++-- apps/openmw/mwgui/enchantingdialog.hpp | 13 +- apps/openmw/mwgui/spellcreationdialog.cpp | 10 +- apps/openmw/mwgui/spellcreationdialog.hpp | 5 +- apps/openmw/mwmechanics/enchanting.cpp | 164 ++++++++++++++++++++++ apps/openmw/mwmechanics/enchanting.hpp | 41 ++++++ apps/openmw/mwworld/class.cpp | 5 + apps/openmw/mwworld/class.hpp | 2 + apps/openmw/mwworld/worldimp.cpp | 25 ++++ apps/openmw/mwworld/worldimp.hpp | 29 +++- 20 files changed, 482 insertions(+), 36 deletions(-) create mode 100644 apps/openmw/mwmechanics/enchanting.cpp create mode 100644 apps/openmw/mwmechanics/enchanting.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 0edc18afba..7b79a8fdf5 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate + aiescort aiactivate enchanting ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 642291eefb..041e2cc1c1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -243,27 +243,44 @@ namespace MWBase ///< Toggle a render mode. ///< \return Resulting mode - virtual const ESM::Potion *createRecord (const ESM::Potion& record) - = 0; - ///< Create a new recrod (of type potion) in the ESM store. + virtual const ESM::Potion *createRecord (const ESM::Potion& record) = 0; + ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record - virtual const ESM::Spell *createRecord (const ESM::Spell& record) - = 0; - ///< Create a new recrod (of type spell) in the ESM store. + virtual const ESM::Spell *createRecord (const ESM::Spell& record) = 0; + ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record - virtual const ESM::Class *createRecord (const ESM::Class& record) - = 0; - ///< Create a new recrod (of type class) in the ESM store. + virtual const ESM::Class *createRecord (const ESM::Class& record) = 0; + ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record virtual const ESM::Cell *createRecord (const ESM::Cell& record) = 0; - ///< Create a new recrod (of type cell) in the ESM store. + ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record virtual const ESM::NPC *createRecord(const ESM::NPC &record) = 0; - ///< Create a new recrod (of type npc) in the ESM store. + ///< Create a new record (of type npc) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Armor *createRecord (const ESM::Armor& record) = 0; + ///< Create a new record (of type armor) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Weapon *createRecord (const ESM::Weapon& record) = 0; + ///< Create a new record (of type weapon) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Clothing *createRecord (const ESM::Clothing& record) = 0; + ///< Create a new record (of type clothing) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record) = 0; + ///< Create a new record (of type enchantment) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Book *createRecord (const ESM::Book& record) = 0; + ///< Create a new record (of type book) in the ESM store. /// \return pointer to created record virtual void update (float duration, bool paused) = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 130c0515d0..02ed743dff 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -273,6 +274,20 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Armor oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Armor newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index ff45411ed2..2c79321bb2 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,6 +65,8 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 4e29fa6845..9714bc06e7 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -11,6 +11,7 @@ #include "../mwworld/actionread.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" +#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -147,6 +148,21 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Book oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Book newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mIsScroll = 1; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const { return boost::shared_ptr(new MWWorld::ActionRead(ptr)); @@ -160,4 +176,12 @@ namespace MWClass return MWWorld::Ptr(&cell.mBooks.insert(*ref), &cell); } + + short Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const + { + MWWorld::LiveCellRef *ref = + ptr.get(); + + return ref->mBase->mData.mEnchant; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index acb1aac06e..950f2be413 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,10 +51,14 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index f5f71a7767..813746fea2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -221,6 +222,20 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Clothing oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Clothing newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index f01c78afce..e705c113bf 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,6 +59,8 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + 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 0f6e86811e..79ed66a501 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -361,6 +362,20 @@ namespace MWClass return ref->mBase->mEnchant; } + MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + ESM::Weapon oldItem = *store.get().find(ptr.getCellRef().mRefID); + ESM::Weapon newItem = oldItem; + newItem.mId=""; + newItem.mName=newName; + newItem.mData.mEnchant=enchCharge; + newItem.mEnchant=enchId; + const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return ref.getPtr(); + } + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index bf34172516..24da3fe64a 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,6 +65,8 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 673739cbf3..5c31a32669 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -5,9 +5,11 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" #include "itemselection.hpp" #include "container.hpp" +#include "inventorywindow.hpp" namespace MWGui { @@ -17,8 +19,9 @@ namespace MWGui : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) , mItemSelectionDialog(NULL) - , mCurrentEnchantmentPoints(0) + , mEnchanting(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) { + getWidget(mName, "NameEdit"); getWidget(mCancelButton, "CancelButton"); getWidget(mAvailableEffectsList, "AvailableEffects"); getWidget(mUsedEffectsView, "UsedEffects"); @@ -36,6 +39,8 @@ namespace MWGui mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onCancelButtonClicked); mItemBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectItem); mSoulBox->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onSelectSoul); + mBuyButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onBuyButtonClicked); + mTypeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onTypeButtonClicked); } EnchantingDialog::~EnchantingDialog() @@ -52,9 +57,32 @@ namespace MWGui void EnchantingDialog::updateLabels() { - mEnchantmentPoints->setCaption(boost::lexical_cast(mCurrentEnchantmentPoints) - + " / " + (mItem.isEmpty() ? "0" : boost::lexical_cast( - MWWorld::Class::get(mItem).getEnchantmentPoints(mItem)))); + mEnchantmentPoints->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost()) + + " / " + boost::lexical_cast(mEnchanting.getMaxEnchantValue())); + + mCharge->setCaption(boost::lexical_cast(mEnchanting.getGemCharge())); + + mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + + switch(mEnchanting.getEnchantType()) + { + case 0: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastOnce","Cast Once")); + mAddEffectDialog.constantEffect=false; + break; + case 1: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenStrikes", "When Strikes")); + mAddEffectDialog.constantEffect=false; + break; + case 2: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenUsed", "When Used")); + mAddEffectDialog.constantEffect=false; + break; + case 3: + mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastConstant", "Cast Constant")); + mAddEffectDialog.constantEffect=true; + break; + } } void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) @@ -105,7 +133,8 @@ namespace MWGui image->setUserData(item); image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveItem); - mItem = item; + mEnchanting.setOldItem(item); + mEnchanting.nextEnchantType(); updateLabels(); } @@ -113,7 +142,7 @@ namespace MWGui { while (mItemBox->getChildCount ()) MyGUI::Gui::getInstance ().destroyWidget (mItemBox->getChildAt(0)); - mItem = MWWorld::Ptr(); + mEnchanting.setOldItem(MWWorld::Ptr()); updateLabels(); } @@ -125,6 +154,13 @@ namespace MWGui void EnchantingDialog::onSoulSelected(MWWorld::Ptr item) { mItemSelectionDialog->setVisible(false); + mEnchanting.setSoulGem(item); + + if(mEnchanting.getGemCharge()==0) + { + mWindowManager.messageBox ("#{sNotifyMessage32}", std::vector()); + return; + } while (mSoulBox->getChildCount ()) MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); @@ -139,8 +175,6 @@ namespace MWGui image->setUserString ("ToolTipType", "ItemPtr"); image->setUserData(item); image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); - - mSoul = item; updateLabels(); } @@ -148,7 +182,7 @@ namespace MWGui { while (mSoulBox->getChildCount ()) MyGUI::Gui::getInstance ().destroyWidget (mSoulBox->getChildAt(0)); - mSoul = MWWorld::Ptr(); + mEnchanting.setSoulGem(MWWorld::Ptr()); updateLabels(); } @@ -170,4 +204,56 @@ namespace MWGui //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); } + + void EnchantingDialog::notifyEffectsChanged () + { + mEffectList.mList = mEffects; + mEnchanting.setEffect(mEffectList); + updateLabels(); + } + + void EnchantingDialog::onTypeButtonClicked(MyGUI::Widget* sender) + { + mEnchanting.nextEnchantType(); + updateLabels(); + } + + void EnchantingDialog::onBuyButtonClicked(MyGUI::Widget* sender) + { + if (mEffects.size() <= 0) + { + mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector()); + return; + } + + if (mName->getCaption ().empty()) + { + mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector()); + return; + } + + if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) + { + mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector()); + return; + } + + if (mEnchanting.soulEmpty()) + { + mWindowManager.messageBox ("#{sNotifyMessage52}", std::vector()); + return; + } + + if (mEnchanting.itemEmpty()) + { + mWindowManager.messageBox ("#{sNotifyMessage11}", std::vector()); + return; + } + + mEnchanting.setNewItemName(mName->getCaption()); + mEnchanting.setEffect(mEffectList); + + mEnchanting.create(); + mWindowManager.removeGuiMode (GM_Enchanting); + } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index bcebb799df..60445a8dc3 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -7,6 +7,8 @@ #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/enchanting.hpp" + namespace MWGui { @@ -23,6 +25,7 @@ namespace MWGui protected: virtual void onReferenceUnavailable(); + virtual void notifyEffectsChanged (); void onCancelButtonClicked(MyGUI::Widget* sender); void onSelectItem (MyGUI::Widget* sender); @@ -34,8 +37,9 @@ namespace MWGui void onItemCancel(); void onSoulSelected(MWWorld::Ptr item); void onSoulCancel(); - + void onBuyButtonClicked(MyGUI::Widget* sender); void updateLabels(); + void onTypeButtonClicked(MyGUI::Widget* sender); ItemSelectionDialog* mItemSelectionDialog; @@ -46,15 +50,14 @@ namespace MWGui MyGUI::Button* mTypeButton; MyGUI::Button* mBuyButton; + MyGUI::TextBox* mName; MyGUI::TextBox* mEnchantmentPoints; MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; MyGUI::TextBox* mPrice; - MWWorld::Ptr mItem; - MWWorld::Ptr mSoul; - - float mCurrentEnchantmentPoints; + MWMechanics::Enchanting mEnchanting; + ESM::EffectList mEffectList; }; } diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 8395864521..ea91ac278f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -72,6 +72,7 @@ namespace MWGui mMagnitudeMaxSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onMagnitudeMaxChanged); mDurationSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onDurationChanged); mAreaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &EditEffectDialog::onAreaChanged); + constantEffect=false; } void EditEffectDialog::open() @@ -164,7 +165,7 @@ namespace MWGui mMagnitudeBox->setVisible (true); curY += mMagnitudeBox->getSize().height; } - if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)&&constantEffect==false) { mDurationBox->setPosition(mDurationBox->getPosition().left, curY); mDurationBox->setVisible (true); @@ -454,10 +455,13 @@ namespace MWGui mAvailableEffectsList->clear (); + int i=0; for (std::vector::const_iterator it = knownEffects.begin(); it != knownEffects.end(); ++it) { mAvailableEffectsList->addItem(MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString()); + mButtonMapping[i] = *it; + ++i; } mAvailableEffectsList->adjustSize (); @@ -466,7 +470,6 @@ namespace MWGui std::string name = MWBase::Environment::get().getWorld ()->getStore ().get().find( ESM::MagicEffect::effectIdToString (*it))->getString(); MyGUI::Widget* w = mAvailableEffectsList->getItemWidget(name); - w->setUserData(*it); ToolTips::createMagicEffectToolTip (w, *it); } @@ -518,7 +521,8 @@ namespace MWGui return; } - short effectId = *sender->getUserData(); + int buttonId = *sender->getUserData(); + short effectId = mButtonMapping[buttonId]; for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 4d27ec1c6f..8f1c071804 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -24,7 +24,7 @@ namespace MWGui void newEffect (const ESM::MagicEffect* effect); void editEffect (ESM::ENAMstruct effect); - + bool constantEffect; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Effect; EventHandle_Effect eventEffectAdded; @@ -69,7 +69,6 @@ namespace MWGui void onMagnitudeMaxChanged (MyGUI::ScrollBar* sender, size_t pos); void onDurationChanged (MyGUI::ScrollBar* sender, size_t pos); void onAreaChanged (MyGUI::ScrollBar* sender, size_t pos); - void setMagicEffect(const ESM::MagicEffect* effect); void updateBoxes(); @@ -88,6 +87,8 @@ namespace MWGui protected: + std::map mButtonMapping; // maps button ID to effect ID + Widgets::MWList* mAvailableEffectsList; MyGUI::ScrollView* mUsedEffectsView; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp new file mode 100644 index 0000000000..d3352226b1 --- /dev/null +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -0,0 +1,164 @@ +#include "enchanting.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/containerstore.hpp" +namespace MWMechanics +{ + Enchanting::Enchanting(MWWorld::Ptr enchanter): + mEnchanter(enchanter), + mEnchantType(0) + {} + + void Enchanting::setOldItem(MWWorld::Ptr oldItem) + { + mOldItemPtr=oldItem; + if(!itemEmpty()) + { + mObjectType = mOldItemPtr.getTypeName(); + mOldItemId = mOldItemPtr.getCellRef().mRefID; + } + else + { + mObjectType=""; + mOldItemId=""; + } + } + + void Enchanting::setNewItemName(std::string s) + { + mNewItemName=s; + } + + void Enchanting::setEffect(ESM::EffectList effectList) + { + mEffectList=effectList; + } + + int Enchanting::getEnchantType() + { + return mEnchantType; + } + + void Enchanting::setSoulGem(MWWorld::Ptr soulGem) + { + mSoulGemPtr=soulGem; + } + + void Enchanting::create() + { + mEnchantment.mData.mCharge = getGemCharge(); + if(mEnchantType==3) + { + mEnchantment.mData.mCharge=0; + } + mEnchantment.mData.mType = mEnchantType; + mEnchantment.mData.mCost = getEnchantCost(); + mEnchantment.mEffects = mEffectList; + const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); + + MWWorld::Ptr newobj = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); + + mOldItemPtr.getRefData().setCount(0); + mSoulGemPtr.getRefData().setCount(0); + } + + void Enchanting::nextEnchantType() + { + mEnchantType++; + if (itemEmpty()) + { + mEnchantType = 0; + return; + } + if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) + { + switch(mEnchantType) + { + case 1: + mEnchantType = 2; + case 3: + if(getGemCharge()<400) + mEnchantType=2; + case 4: + mEnchantType = 2; + } + } + else if(mObjectType == typeid(ESM::Weapon).name()) + { + switch(mEnchantType) + { + case 3: + mEnchantType = 1; + } + } + else if(mObjectType == typeid(ESM::Book).name()) + { + mEnchantType=0; + } + } + + int Enchanting::getEnchantCost() + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + float cost = 0; + std::vector mEffects = mEffectList.mList; + int i=mEffects.size(); + for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) + { + const ESM::MagicEffect* effect = store.get().find(it->mEffectID); + + float cost1 = ((it->mMagnMin + it->mMagnMax)*it->mDuration*effect->mData.mBaseCost*0.025); + + float cost2 = (std::max(1, it->mArea)*0.125*effect->mData.mBaseCost); + + if(mEnchantType==3) + { + cost1 *= 100; + cost2 *= 2; + } + if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) + cost1 *= 1.5; + + float fullcost = cost1+cost2; + fullcost*= i; + i--; + + cost+=fullcost; + } + return cost; + } + int Enchanting::getGemCharge() + { + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + if(soulEmpty()) + return 0; + if(mSoulGemPtr.getCellRef().mSoul=="") + return 0; + const ESM::Creature* soul = store.get().find(mSoulGemPtr.getCellRef().mSoul); + return soul->mData.mSoul; + } + + int Enchanting::getMaxEnchantValue() + { + if (itemEmpty()) + return 0; + return MWWorld::Class::get(mOldItemPtr).getEnchantmentPoints(mOldItemPtr); + } + bool Enchanting::soulEmpty() + { + if (mSoulGemPtr.isEmpty()) + return true; + return false; + } + + bool Enchanting::itemEmpty() + { + if(mOldItemPtr.isEmpty()) + return true; + return false; + } +} diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp new file mode 100644 index 0000000000..1daf34c6d1 --- /dev/null +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -0,0 +1,41 @@ +#ifndef GAME_MWMECHANICS_ENCHANTING_H +#define GAME_MWMECHANICS_ENCHANTING_H +#include +#include "../mwworld/ptr.hpp" +#include +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +namespace MWMechanics +{ + class Enchanting + { + + MWWorld::Ptr mOldItemPtr; + MWWorld::Ptr mSoulGemPtr; + MWWorld::Ptr mEnchanter; + const MWWorld::Ptr *mNewItemPtr; + int mEnchantType; + + ESM::EffectList mEffectList; + ESM::Enchantment mEnchantment; + + std::string mNewItemName; + std::string mObjectType; + std::string mOldItemId; + public: + Enchanting(MWWorld::Ptr enchanter); + void setOldItem(MWWorld::Ptr oldItem); + void setNewItemName(std::string s); + void setEffect(ESM::EffectList effectList); + void setSoulGem(MWWorld::Ptr soulGem); + void create(); + void nextEnchantType(); + int getEnchantType(); + int getEnchantCost(); + int getMaxEnchantValue(); + int getGemCharge(); + bool soulEmpty(); + bool itemEmpty(); + }; +} +#endif diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index cc20aeda75..28aa14e8e6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,6 +241,11 @@ namespace MWWorld return ""; } + MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + { + throw std::runtime_error ("class can't be enchanted"); + } + MWWorld::Ptr Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 77c29fe489..ae75137f5f 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,6 +231,8 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 5a23aae972..81b33a55b4 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -948,6 +948,31 @@ namespace MWWorld return ret; } + const ESM::Armor *World::createRecord (const ESM::Armor& record) + { + return mStore.insert(record); + } + + const ESM::Weapon *World::createRecord (const ESM::Weapon& record) + { + return mStore.insert(record); + } + + const ESM::Clothing *World::createRecord (const ESM::Clothing& record) + { + return mStore.insert(record); + } + + const ESM::Enchantment *World::createRecord (const ESM::Enchantment& record) + { + return mStore.insert(record); + } + + const ESM::Book *World::createRecord (const ESM::Book& record) + { + return mStore.insert(record); + } + void World::update (float duration, bool paused) { mWeatherManager->update (duration); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 526e68a77a..ea318299f2 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -272,25 +272,44 @@ namespace MWWorld ///< \return Resulting mode virtual const ESM::Potion *createRecord (const ESM::Potion& record); - ///< Create a new recrod (of type potion) in the ESM store. + ///< Create a new record (of type potion) in the ESM store. /// \return pointer to created record virtual const ESM::Spell *createRecord (const ESM::Spell& record); - ///< Create a new recrod (of type spell) in the ESM store. + ///< Create a new record (of type spell) in the ESM store. /// \return pointer to created record virtual const ESM::Class *createRecord (const ESM::Class& record); - ///< Create a new recrod (of type class) in the ESM store. + ///< Create a new record (of type class) in the ESM store. /// \return pointer to created record virtual const ESM::Cell *createRecord (const ESM::Cell& record); - ///< Create a new recrod (of type cell) in the ESM store. + ///< Create a new record (of type cell) in the ESM store. /// \return pointer to created record virtual const ESM::NPC *createRecord(const ESM::NPC &record); - ///< Create a new recrod (of type npc) in the ESM store. + ///< Create a new record (of type npc) in the ESM store. /// \return pointer to created record + virtual const ESM::Armor *createRecord (const ESM::Armor& record); + ///< Create a new record (of type armor) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Weapon *createRecord (const ESM::Weapon& record); + ///< Create a new record (of type weapon) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Clothing *createRecord (const ESM::Clothing& record); + ///< Create a new record (of type clothing) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Enchantment *createRecord (const ESM::Enchantment& record); + ///< Create a new record (of type enchantment) in the ESM store. + /// \return pointer to created record + + virtual const ESM::Book *createRecord (const ESM::Book& record); + ///< Create a new record (of type book) in the ESM store. + /// \return pointer to created record virtual void update (float duration, bool paused); From eb88463b9419339bc0ba2bd8e55c16cc6b736af4 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 28 Mar 2013 23:39:20 +0100 Subject: [PATCH 0150/1537] Some enchanting fixes --- apps/openmw/mwclass/armor.cpp | 13 +++++++------ apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 13 +++++++------ apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 13 +++++++------ apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 13 +++++++------ apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwmechanics/enchanting.cpp | 4 ++-- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 11 files changed, 36 insertions(+), 32 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 02ed743dff..a691365747 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -274,18 +274,19 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Armor oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Armor newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Armor newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 2c79321bb2..e987c48010 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 9714bc06e7..5e73dcfd43 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -148,19 +148,20 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Book oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Book newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Book newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mIsScroll = 1; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 950f2be413..b27ae78cee 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; 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 813746fea2..cfef27c422 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -222,18 +222,19 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Clothing oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Clothing newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Clothing newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index e705c113bf..d929824ffd 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 79ed66a501..b17481f188 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -362,18 +362,19 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - ESM::Weapon oldItem = *store.get().find(ptr.getCellRef().mRefID); - ESM::Weapon newItem = oldItem; + MWWorld::LiveCellRef *ref = + ptr.get(); + + ESM::Weapon newItem = *ref->mBase; newItem.mId=""; newItem.mName=newName; newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return ref.getPtr(); + MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); + return mref.getPtr(); } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 24da3fe64a..561f2403f2 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d3352226b1..2d90f62b05 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -62,8 +62,8 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - mOldItemPtr.getRefData().setCount(0); - mSoulGemPtr.getRefData().setCount(0); + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); } void Enchanting::nextEnchantType() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 28aa14e8e6..88f9d75505 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,7 +241,7 @@ namespace MWWorld return ""; } - MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const + MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index ae75137f5f..2c4034616e 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,7 +231,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, std::string enchId, int enchCharge, std::string newName) const; + virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From cc8f7f238ef5a620e4103dd58c06d7aa09cc3e96 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 29 Mar 2013 00:55:29 +0100 Subject: [PATCH 0151/1537] Enchanted item base ptr fix --- apps/openmw/mwmechanics/enchanting.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 2d90f62b05..a8e23ed1fc 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -60,6 +60,7 @@ namespace MWMechanics MWWorld::Ptr newobj = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); + newobj.mPtr = mOldItemPtr.mPtr; MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); From c5f05564511769974dffa0b7097b2072b605ce86 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 28 Mar 2013 20:57:33 -0700 Subject: [PATCH 0152/1537] Handle light linear/quadratic settings --- apps/openmw/mwrender/objects.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 23d35c65f0..892b30ca14 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -271,16 +271,11 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre info.time = Ogre::Math::RangeRandom(-500, +500); info.phase = Ogre::Math::RangeRandom(-500, +500); - // changed to linear to look like morrowind - bool quadratic = false; - /* - if (!lightOutQuadInLin) - quadratic = lightQuadratic; + bool quadratic; + if (!lightOutQuadInLin()) + quadratic = lightQuadratic(); else - { quadratic = !info.interior; - } - */ if (!quadratic) { From e7684c4677c610c00c0b155e362194724dbb58fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 29 Mar 2013 09:04:02 +0100 Subject: [PATCH 0153/1537] some random cleanup --- apps/openmw/mwrender/objects.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 892b30ca14..5cf4abdf77 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -1,5 +1,7 @@ #include "objects.hpp" +#include + #include #include #include @@ -271,11 +273,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre info.time = Ogre::Math::RangeRandom(-500, +500); info.phase = Ogre::Math::RangeRandom(-500, +500); - bool quadratic; - if (!lightOutQuadInLin()) - quadratic = lightQuadratic(); - else - quadratic = !info.interior; + bool quadratic = lightOutQuadInLin() ? !info.interior : lightQuadratic(); if (!quadratic) { @@ -286,7 +284,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre else { float r = radius * lightQuadraticRadiusMult(); - float attenuation = lightQuadraticValue() / pow(r, 2); + float attenuation = lightQuadraticValue() / std::pow(r, 2); light->setAttenuation(r*10, 0, 0, attenuation); } From 86275e5bd4f0df24bb95d00abc0bace49d1383fa Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 29 Mar 2013 12:00:09 +0100 Subject: [PATCH 0154/1537] Some enchanting fixes --- apps/openmw/mwclass/armor.cpp | 6 ++---- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 6 ++---- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 ++---- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 6 ++---- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 16 +++++++++------- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 12 files changed, 24 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a691365747..b29cbb3d11 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,7 +16,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -274,7 +273,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -285,8 +284,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index e987c48010..0c32015a35 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 5e73dcfd43..644561e52b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -11,7 +11,6 @@ #include "../mwworld/actionread.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" -#include "../mwworld/manualref.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -148,7 +147,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -160,8 +159,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index b27ae78cee..c17d4255b1 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; 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 cfef27c422..8f29a2084d 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,7 +14,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -222,7 +221,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -233,8 +232,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index d929824ffd..4457e79fb6 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index b17481f188..302dc47daa 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -14,7 +14,6 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" -#include "../mwworld/manualref.hpp" #include "../mwgui/tooltips.hpp" @@ -362,7 +361,7 @@ namespace MWClass return ref->mBase->mEnchant; } - MWWorld::Ptr Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -373,8 +372,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - MWWorld::ManualRef mref (MWBase::Environment::get().getWorld()->getStore(), record->mId); - return mref.getPtr(); + return record->mId; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 561f2403f2..533f32f592 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ 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 MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 5c31a32669..6114bd4649 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -254,6 +254,7 @@ namespace MWGui mEnchanting.setEffect(mEffectList); mEnchanting.create(); + mWindowManager.messageBox ("#{sEnchantmentMenu12}", std::vector()); mWindowManager.removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a8e23ed1fc..4ef20a5e52 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -47,6 +47,9 @@ namespace MWMechanics void Enchanting::create() { + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { @@ -57,14 +60,13 @@ namespace MWMechanics mEnchantment.mEffects = mEffectList; const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); - MWWorld::Ptr newobj = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + std::string newobjId = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobj.getCellRef().mRefID); - newobj.mPtr = mOldItemPtr.mPtr; - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); - mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobjId); + MWWorld::Ptr newobjPtr = ref.getPtr(); + MWWorld::Ptr result = mOldItemPtr; + result.mPtr = newobjPtr.mPtr; + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); } void Enchanting::nextEnchantType() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 88f9d75505..4af0869a31 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -241,7 +241,7 @@ namespace MWWorld return ""; } - MWWorld::Ptr Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 2c4034616e..56189dafde 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -231,7 +231,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual MWWorld::Ptr applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From a39c129954ea7cfb318f32d14644212e648a1aed Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 Mar 2013 19:53:52 +0100 Subject: [PATCH 0155/1537] Clamp individual light attenuation at 1 --- files/materials/objects.shader | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index ae589a05be..c8616e9d1e 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -146,11 +146,11 @@ #if VERTEXCOLOR_MODE == 2 lightResult.xyz += colour.xyz * lightDiffuse[@shIterator].xyz - * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) * max(dot(viewNormal.xyz, lightDir), 0); #else lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz - * (1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) * max(dot(viewNormal.xyz, lightDir), 0); #endif From 5e7e9fd26aa2f48687e843d47ab287161b1ed82a Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 29 Mar 2013 20:21:37 +0100 Subject: [PATCH 0156/1537] Properly calculate light activation range --- apps/openmw/mwrender/objects.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 5cf4abdf77..50c0210649 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -275,17 +275,23 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, Ogre::Entity* skelBase, Ogre bool quadratic = lightOutQuadInLin() ? !info.interior : lightQuadratic(); + // with the standard 1 / (c + d*l + d*d*q) equation the attenuation factor never becomes zero, + // so we ignore lights if their attenuation falls below this factor. + const float threshold = 0.03; + if (!quadratic) { float r = radius * lightLinearRadiusMult(); float attenuation = lightLinearValue() / r; - light->setAttenuation(r*10, 0, attenuation, 0); + float activationRange = 1 / (threshold * attenuation); + light->setAttenuation(activationRange, 0, attenuation, 0); } else { float r = radius * lightQuadraticRadiusMult(); float attenuation = lightQuadraticValue() / std::pow(r, 2); - light->setAttenuation(r*10, 0, 0, attenuation); + float activationRange = std::sqrt(1 / (threshold * attenuation)); + light->setAttenuation(activationRange, 0, 0, attenuation); } // If there's an AttachLight bone, attach the light to that, otherwise attach it to the base scene node From 35a6ca010ae0ff99b0c3e0cae5477ccfe5f29d3a Mon Sep 17 00:00:00 2001 From: vorenon Date: Fri, 29 Mar 2013 20:43:17 +0100 Subject: [PATCH 0157/1537] Adjusted textbox height in race menu --- files/mygui/openmw_chargen_race.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index c0b04618ed..aaa5b4b502 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + From f93cefa201e1e3cf194011e45dbe71c24e822ce5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Fri, 29 Mar 2013 21:26:40 +0100 Subject: [PATCH 0158/1537] Changed Y position of the textboxes --- files/mygui/openmw_chargen_race.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index aaa5b4b502..a27d271917 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + From a49e52454108a591e87431797335cae83c8338c5 Mon Sep 17 00:00:00 2001 From: vorenon Date: Sat, 30 Mar 2013 03:07:34 +0100 Subject: [PATCH 0159/1537] Reduced width of textboxes in race menu The width of the text box was too large and MyGui didn't align the texts properly. Fixed with the help of the MyGui layout editor. --- files/mygui/openmw_chargen_race.layout | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index a27d271917..c569abb863 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -22,7 +22,7 @@ - + @@ -34,7 +34,7 @@ - + @@ -46,7 +46,7 @@ - + From 04673b2f14f2572e9b2a6d5d98c066f3b778d3b5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 12:54:20 +0100 Subject: [PATCH 0160/1537] Don't enchant if the enchantment value is too high for the item --- apps/openmw/mwgui/enchantingdialog.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 6114bd4649..536dafc01a 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -158,7 +158,7 @@ namespace MWGui if(mEnchanting.getGemCharge()==0) { - mWindowManager.messageBox ("#{sNotifyMessage32}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage32}"); return; } @@ -222,31 +222,37 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage30}"); return; } if (mName->getCaption ().empty()) { - mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage10}"); return; } if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage18}"); return; } if (mEnchanting.soulEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage52}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage52}"); return; } if (mEnchanting.itemEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage11}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage11}"); + return; + } + + if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) + { + mWindowManager.messageBox ("#{sNotifyMessage29}"); return; } @@ -254,7 +260,7 @@ namespace MWGui mEnchanting.setEffect(mEffectList); mEnchanting.create(); - mWindowManager.messageBox ("#{sEnchantmentMenu12}", std::vector()); + mWindowManager.messageBox ("#{sEnchantmentMenu12}"); mWindowManager.removeGuiMode (GM_Enchanting); } } From e7af718b55a8a436ddc950bd47a0ebfb4a7a0e9d Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 12:56:37 +0100 Subject: [PATCH 0161/1537] Remove unnecessary WindowManager::messageBox arguments --- apps/openmw/mwclass/container.cpp | 2 +- apps/openmw/mwclass/door.cpp | 2 +- apps/openmw/mwgui/alchemywindow.cpp | 12 ++++++------ apps/openmw/mwgui/container.cpp | 6 +++--- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ++-- apps/openmw/mwgui/settingswindow.cpp | 4 ++-- apps/openmw/mwgui/spellcreationdialog.cpp | 12 ++++++------ apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/text_input.cpp | 4 ++-- apps/openmw/mwgui/tradewindow.cpp | 10 +++++----- apps/openmw/mwgui/trainingwindow.cpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 2 +- apps/openmw/mwmechanics/npcstats.cpp | 4 ++-- apps/openmw/mwscript/containerextensions.cpp | 4 ++-- apps/openmw/mwworld/actionequip.cpp | 6 +++--- apps/openmw/mwworld/failedaction.cpp | 2 +- 18 files changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index a2d75131eb..4ee95b96e1 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -115,7 +115,7 @@ namespace MWClass if (needKey && hasKey) { - MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); ptr.getCellRef().mLockLevel = 0; // using a key disarms the trap ptr.getCellRef().mTrap = ""; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index fb63299397..163cf02775 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -98,7 +98,7 @@ namespace MWClass if (needKey && hasKey) { - MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox (keyName + " #{sKeyUsed}"); ptr.getCellRef().mLockLevel = 0; // using a key disarms the trap ptr.getCellRef().mTrap = ""; diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index fce6126001..ca7f1b913a 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -77,40 +77,40 @@ namespace MWGui if (result == MWMechanics::Alchemy::Result_NoName) { - mWindowManager.messageBox("#{sNotifyMessage37}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage37}"); return; } // check if mortar & pestle is available (always needed) if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) { - mWindowManager.messageBox("#{sNotifyMessage45}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage45}"); return; } // make sure 2 or more ingredients were selected if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) { - mWindowManager.messageBox("#{sNotifyMessage6a}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage6a}"); return; } if (result == MWMechanics::Alchemy::Result_NoEffects) { - mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); return; } if (result == MWMechanics::Alchemy::Result_Success) { - mWindowManager.messageBox("#{sPotionSuccess}", std::vector()); + mWindowManager.messageBox("#{sPotionSuccess}"); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); } else if (result == MWMechanics::Alchemy::Result_RandomFailure) { // potion failed - mWindowManager.messageBox("#{sNotifyMessage8}", std::vector()); + mWindowManager.messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); } diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0a674ba82c..98d818638a 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -150,7 +150,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) { // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog4}", std::vector()); + messageBox("#{sBarterDialog4}"); return; } } @@ -294,7 +294,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}", std::vector()); + messageBox("#{sContentsMessage2}"); return; } @@ -318,7 +318,7 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) object.getRefData().setCount(origCount); // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage3}", std::vector()); + messageBox("#{sContentsMessage3}"); return; } diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index f0a3858084..67620d49da 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -162,7 +162,7 @@ namespace MWGui MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); if (mSpentAttributes.size() < 3) - MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}"); else { // increase attributes diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 6d51420f01..5ea13fb0d7 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -291,7 +291,7 @@ namespace MWGui if (item.getRefData ().getCount() == 0) { MWBase::Environment::get().getWindowManager ()->messageBox ( - "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item), std::vector()); + "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item)); return; } @@ -317,7 +317,7 @@ namespace MWGui if (item.getRefData ().getCount() == 0) { MWBase::Environment::get().getWindowManager ()->messageBox ( - "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item), std::vector()); + "#{sQuickMenu5} " + MWWorld::Class::get(item).getName(item)); return; } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 04856c3ed9..58754472dd 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -362,7 +362,7 @@ namespace MWGui { 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()); + messageBox(msg); _sender->castType()->setCaption(off); } else @@ -593,7 +593,7 @@ namespace MWGui static_cast(_sender)->setCaptionWithReplacing("#{sNone}"); - MWBase::Environment::get().getWindowManager ()->messageBox ("#{sControlsMenu3}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sControlsMenu3}"); MWBase::Environment::get().getWindowManager ()->disallowMouse(); MWBase::Environment::get().getInputManager ()->enableDetectingBindingMode (actionId); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index ea91ac278f..592063a761 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -310,25 +310,25 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage30}"); return; } if (mNameEdit->getCaption () == "") { - mWindowManager.messageBox ("#{sNotifyMessage10}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage10}"); return; } if (mMagickaCost->getCaption() == "0") { - mWindowManager.messageBox ("#{sEnchantmentMenu8}", std::vector()); + mWindowManager.messageBox ("#{sEnchantmentMenu8}"); return; } if (boost::lexical_cast(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage18}"); return; } @@ -517,7 +517,7 @@ namespace MWGui { if (mEffects.size() >= 8) { - MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage28}"); return; } @@ -528,7 +528,7 @@ namespace MWGui { if (it->mEffectID == effectId) { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sOnetypeEffectMessage}"); return; } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 50691d5540..d7fb0e1bcd 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -404,7 +404,7 @@ namespace MWGui if (spell->mData.mFlags & ESM::Spell::F_Always || spell->mData.mType == ESM::Spell::ST_Power) { - mWindowManager.messageBox("#{sDeleteSpellError}", std::vector()); + mWindowManager.messageBox("#{sDeleteSpellError}"); } else { diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 9265cadf94..ee9144be68 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -50,7 +50,7 @@ void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { if (mTextEdit->getCaption() == "") { - mWindowManager.messageBox ("#{sNotifyMessage37}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage37}"); MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); } else @@ -61,7 +61,7 @@ void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) { if (mTextEdit->getCaption() == "") { - mWindowManager.messageBox ("#{sNotifyMessage37}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage37}"); MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); } else diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f84a0abc88..307533d91a 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -181,7 +181,7 @@ namespace MWGui { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog11}", std::vector()); + messageBox("#{sBarterDialog11}"); return; } @@ -190,7 +190,7 @@ namespace MWGui { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog1}", std::vector()); + messageBox("#{sBarterDialog1}"); return; } @@ -199,7 +199,7 @@ namespace MWGui { // user notification MWBase::Environment::get().getWindowManager()-> - messageBox("#{sBarterDialog2}", std::vector()); + messageBox("#{sBarterDialog2}"); return; } @@ -209,7 +209,7 @@ namespace MWGui if (mPtr.getTypeName() != typeid(ESM::NPC).name()) { MWBase::Environment::get().getWindowManager()-> - messageBox("#{sNotifyMessage9}", std::vector()); + messageBox("#{sNotifyMessage9}"); return; } @@ -245,7 +245,7 @@ namespace MWGui if(roll > x) //trade refused { MWBase::Environment::get().getWindowManager()-> - messageBox("#{sNotifyMessage9}", std::vector()); + messageBox("#{sNotifyMessage9}"); int iBarterFailDisposition = gmst.find("iBarterFailDisposition")->getInt(); MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index ba39ee601c..601b44d6c9 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -129,7 +129,7 @@ namespace MWGui MWMechanics::NpcStats& npcStats = MWWorld::Class::get(mPtr).getNpcStats (mPtr); if (npcStats.getSkill (skillId).getBase () <= pcStats.getSkill (skillId).getBase ()) { - mWindowManager.messageBox ("#{sServiceTrainingWords}", std::vector()); + mWindowManager.messageBox ("#{sServiceTrainingWords}"); return; } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index df8a52456c..09eb5c914e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -83,7 +83,7 @@ namespace MWGui if (canRest == 2) { // resting underwater or mid-air not allowed - mWindowManager.messageBox ("#{sNotifyMessage1}", std::vector()); + mWindowManager.messageBox ("#{sNotifyMessage1}"); mWindowManager.popGuiMode (); } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1480b3182e..c8d87b425c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -256,7 +256,7 @@ namespace MWMechanics if(MWWorld::Class::get(iter->first).isEssential(iter->first)) MWBase::Environment::get().getWindowManager()->messageBox( - "#{sKilledEssential}", std::vector()); + "#{sKilledEssential}"); } } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 26c4c8e9ac..51e23d16ea 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -221,12 +221,12 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") % static_cast (base); - MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox(message.str()); if (mLevelProgress >= 10) { // levelup is possible now - MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", std::vector()); + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}"); } getSkill (skillIndex).setBase (base); diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 81639b5be9..1154b06c6c 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -83,7 +83,7 @@ namespace MWScript msgBox = boost::str(boost::format(msgBox) % count % itemName); } - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox); } } }; @@ -179,7 +179,7 @@ namespace MWScript } if (numRemoved > 0) - MWBase::Environment::get().getWindowManager()->messageBox(msgBox, std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox(msgBox); } } }; diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index eb2ae9dca7..afbb505f22 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -62,7 +62,7 @@ namespace MWWorld if((*itr).mPart == ESM::PRT_Head) { if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); allow = false; break; @@ -90,12 +90,12 @@ namespace MWWorld if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } else // It's boots { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}", std::vector()); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); } } break; diff --git a/apps/openmw/mwworld/failedaction.cpp b/apps/openmw/mwworld/failedaction.cpp index ec763dba01..1db00ad06c 100644 --- a/apps/openmw/mwworld/failedaction.cpp +++ b/apps/openmw/mwworld/failedaction.cpp @@ -15,7 +15,7 @@ namespace MWWorld { if ( actor.getRefData().getHandle()=="player" && !(message.empty())) { - MWBase::Environment::get().getWindowManager() ->messageBox(message, std::vector()); + MWBase::Environment::get().getWindowManager() ->messageBox(message); } } } From 51204f098e77b7fc7767956045e1625eef7dbd84 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 15:51:07 +0100 Subject: [PATCH 0162/1537] Added soulgem dialog; made interactive message boxes not close the previous UI --- apps/openmw/CMakeLists.txt | 4 +-- apps/openmw/mwbase/windowmanager.hpp | 3 +++ apps/openmw/mwclass/misc.cpp | 10 ++++++++ apps/openmw/mwclass/misc.hpp | 4 +++ apps/openmw/mwgui/enchantingdialog.cpp | 5 ++++ apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwgui/messagebox.cpp | 21 ++++++++------- apps/openmw/mwgui/messagebox.hpp | 9 ++++++- apps/openmw/mwgui/mode.hpp | 4 +-- apps/openmw/mwgui/soulgemdialog.cpp | 34 +++++++++++++++++++++++++ apps/openmw/mwgui/soulgemdialog.hpp | 28 ++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 29 +++++++++++++-------- apps/openmw/mwgui/windowmanagerimp.hpp | 7 +++++ apps/openmw/mwinput/inputmanagerimp.cpp | 8 +++--- apps/openmw/mwworld/actionsoulgem.cpp | 21 +++++++++++++++ apps/openmw/mwworld/actionsoulgem.hpp | 19 ++++++++++++++ 16 files changed, 177 insertions(+), 30 deletions(-) create mode 100644 apps/openmw/mwgui/soulgemdialog.cpp create mode 100644 apps/openmw/mwgui/soulgemdialog.hpp create mode 100644 apps/openmw/mwworld/actionsoulgem.cpp create mode 100644 apps/openmw/mwworld/actionsoulgem.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9b1e5a02fe..41f56f9931 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair + merchantrepair repair soulgemdialog ) add_openmw_dir (mwdialogue @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair + esmstore store recordcmp fallback actionrepair actionsoulgem ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 6760c89d07..58897dc740 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -237,10 +237,13 @@ namespace MWBase virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; + virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; virtual void startTraining(MWWorld::Ptr actor) = 0; virtual void startRepair(MWWorld::Ptr actor) = 0; virtual void startRepairItem(MWWorld::Ptr item) = 0; + virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; + virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b971fa6f34..b8a928becb 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -15,6 +15,7 @@ #include "../mwworld/physicssystem.hpp" #include "../mwworld/manualref.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/actionsoulgem.hpp" #include "../mwgui/tooltips.hpp" @@ -233,4 +234,13 @@ namespace MWClass } return newPtr; } + + boost::shared_ptr Miscellaneous::use (const MWWorld::Ptr& ptr) const + { + if (ptr.getCellRef().mSoul == "") + return boost::shared_ptr(new MWWorld::NullAction()); + else + return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); + } + } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index a5a79a8f6d..12a50af19d 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -49,6 +49,10 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 536dafc01a..ef124bb430 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -92,6 +92,11 @@ namespace MWGui startEditing (); } + void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) + { + /// \todo + } + void EnchantingDialog::onReferenceUnavailable () { mWindowManager.removeGuiMode (GM_Dialogue); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 60445a8dc3..347b37e908 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -22,6 +22,7 @@ namespace MWGui virtual void open(); void startEnchanting(MWWorld::Ptr actor); + void startSelfEnchanting(MWWorld::Ptr soulgem); protected: virtual void onReferenceUnavailable(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index b8a34c457e..46663b67a5 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -3,6 +3,7 @@ #include "messagebox.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" +#include "../mwbase/inputmanager.hpp" using namespace MWGui; @@ -62,7 +63,8 @@ void MessageBoxManager::onFrame (float frameDuration) if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { delete mInterMessageBoxe; mInterMessageBoxe = NULL; - mWindowManager->removeGuiMode(GM_InterMessageBox); + MWBase::Environment::get().getInputManager()->changeInputMode( + MWBase::Environment::get().getWindowManager()->isGuiMode()); } } @@ -90,11 +92,8 @@ void MessageBoxManager::createMessageBox (const std::string& message) bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) { - /// \todo Don't write this kind of error message to cout. Either discard the old message box - /// silently or throw an exception. if(mInterMessageBoxe != NULL) { - std::cout << "there is a MessageBox already" << std::endl; - return false; + throw std::runtime_error("There is a message box already"); } mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); @@ -139,7 +138,8 @@ void MessageBoxManager::setMessageBoxSpeed (int speed) void MessageBoxManager::enterPressed () { - mInterMessageBoxe->enterPressed(); + if(mInterMessageBoxe != NULL) + mInterMessageBoxe->enterPressed(); } int MessageBoxManager::readPressedButton () @@ -213,10 +213,12 @@ int MessageBox::getHeight () InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : Layout("openmw_interactive_messagebox.layout") + : WindowModal("openmw_interactive_messagebox.layout", *MWBase::Environment::get().getWindowManager()) , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { + WindowModal::open(); + int fixedWidth = 500; int textPadding = 10; // padding between text-widget and main-widget int textButtonPadding = 20; // padding between the text-widget und the button-widget @@ -232,7 +234,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan getWidget(mButtonsWidget, "buttons"); mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->addText(message); + mMessageWidget->setCaptionWithReplacing(message); MyGUI::IntSize textSize = mMessageWidget->getTextSize(); @@ -252,7 +254,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan std::string("MW_Button"), dummyCoord, MyGUI::Align::Default); - button->setCaption(*it); + button->setCaptionWithReplacing(*it); button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); @@ -399,6 +401,7 @@ void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) if(*button == pressed) { mButtonPressed = index; + mMessageBoxManager.onButtonPressed(mButtonPressed); return; } index++; diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 149aa7e7f1..859e1806a7 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -44,6 +44,13 @@ namespace MWGui void enterPressed(); int readPressedButton (); + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Int; + + // Note: this delegate unassigns itself after it was fired, i.e. works once. + EventHandle_Int eventButtonPressed; + + void onButtonPressed(int button) { eventButtonPressed(button); eventButtonPressed.clear(); } + MWBase::WindowManager *mWindowManager; private: @@ -73,7 +80,7 @@ namespace MWGui int mNextBoxPadding; }; - class InteractiveMessageBox : public OEngine::GUI::Layout + class InteractiveMessageBox : public WindowModal { public: InteractiveMessageBox (MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons); diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 4091f47acc..e9b01395f0 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -5,6 +5,7 @@ namespace MWGui { enum GuiMode { + GM_None, GM_Settings, // Settings window GM_Inventory, // Inventory mode GM_Container, @@ -41,9 +42,6 @@ namespace MWGui GM_ClassCreate, GM_Review, - // interactive MessageBox - GM_InterMessageBox, - GM_Loading, GM_LoadingWallpaper, diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp new file mode 100644 index 0000000000..4530a13d0b --- /dev/null +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -0,0 +1,34 @@ +#include "soulgemdialog.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +#include "messagebox.hpp" + +namespace MWGui +{ + + void SoulgemDialog::show(const MWWorld::Ptr &soulgem) + { + mSoulgem = soulgem; + std::vector buttons; + buttons.push_back("#{sRechargeEnchantment}"); + buttons.push_back("#{sMake Enchantment}"); + mManager->createInteractiveMessageBox("#{sDoYouWantTo}", buttons); + mManager->eventButtonPressed += MyGUI::newDelegate(this, &SoulgemDialog::onButtonPressed); + } + + void SoulgemDialog::onButtonPressed(int button) + { + if (button == 0) + { + /// \todo show recharge enchanted item dialog here + } + else + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startSelfEnchanting(mSoulgem); + } + } + +} diff --git a/apps/openmw/mwgui/soulgemdialog.hpp b/apps/openmw/mwgui/soulgemdialog.hpp new file mode 100644 index 0000000000..9aea1f3393 --- /dev/null +++ b/apps/openmw/mwgui/soulgemdialog.hpp @@ -0,0 +1,28 @@ +#ifndef OPENMW_MWGUI_SOULGEMDIALOG_H +#define OPENMW_MWGUI_SOULGEMDIALOG_H + +#include "../mwworld/ptr.hpp" + +namespace MWGui +{ + + class MessageBoxManager; + + class SoulgemDialog + { + public: + SoulgemDialog (MessageBoxManager* manager) + : mManager(manager) {} + + void show (const MWWorld::Ptr& soulgem); + + void onButtonPressed(int button); + + private: + MessageBoxManager* mManager; + MWWorld::Ptr mSoulgem; + }; + +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 718bb7106e..eadd657871 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -57,6 +57,7 @@ #include "spellicons.hpp" #include "merchantrepair.hpp" #include "repair.hpp" +#include "soulgemdialog.hpp" using namespace MWGui; @@ -94,6 +95,7 @@ WindowManager::WindowManager( , mTrainingWindow(NULL) , mMerchantRepair(NULL) , mRepair(NULL) + , mSoulgemDialog(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -186,6 +188,7 @@ WindowManager::WindowManager( mTrainingWindow = new TrainingWindow(*this); mMerchantRepair = new MerchantRepair(*this); mRepair = new Repair(*this); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -253,6 +256,7 @@ WindowManager::~WindowManager() delete mQuickKeysMenu; delete mMerchantRepair; delete mRepair; + delete mSoulgemDialog; delete mCursor; cleanupGarbage(); @@ -316,9 +320,6 @@ void WindowManager::updateVisible() mHud->setVisible(mHudEnabled); - // Mouse is visible whenever we're not in game mode - mCursor->setVisible(isGuiMode()); - bool gameMode = !isGuiMode(); mInputBlocker->setVisible (gameMode); @@ -444,8 +445,6 @@ void WindowManager::updateVisible() case GM_Repair: mRepair->setVisible(true); break; - case GM_InterMessageBox: - break; case GM_Journal: mJournal->setVisible(true); break; @@ -609,7 +608,7 @@ void WindowManager::messageBox (const std::string& message, const std::vectorcreateInteractiveMessageBox(message, buttons); - pushGuiMode(GM_InterMessageBox); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); } } @@ -648,6 +647,7 @@ void WindowManager::onDialogueWindowBye() void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); + mToolTips->onFrame(frameDuration); if (mDragAndDrop->mIsOnDragAndDrop) @@ -1033,12 +1033,12 @@ void WindowManager::toggleVisible (GuiWindow wnd) bool WindowManager::isGuiMode() const { - return !mGuiModes.empty(); + return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); } bool WindowManager::isConsoleMode() const { - if (mGuiModes.back()==GM_Console) + if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) return true; return false; } @@ -1046,8 +1046,7 @@ bool WindowManager::isConsoleMode() const MWGui::GuiMode WindowManager::getMode() const { if (mGuiModes.empty()) - throw std::runtime_error ("getMode() called, but there is no active mode"); - + return GM_None; return mGuiModes.back(); } @@ -1143,6 +1142,11 @@ void WindowManager::startEnchanting (MWWorld::Ptr actor) mEnchantingDialog->startEnchanting (actor); } +void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) +{ + mEnchantingDialog->startSelfEnchanting(soulgem); +} + void WindowManager::startTraining(MWWorld::Ptr actor) { mTrainingWindow->startTraining(actor); @@ -1167,3 +1171,8 @@ void WindowManager::changePointer(const std::string &name) { mCursor->onCursorChange(name); } + +void WindowManager::showSoulgemDialog(MWWorld::Ptr item) +{ + mSoulgemDialog->show(item); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 216ab9a6f8..5cf7bae02d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -76,6 +76,7 @@ namespace MWGui class SpellIcons; class MerchantRepair; class Repair; + class SoulgemDialog; class WindowManager : public MWBase::WindowManager { @@ -230,14 +231,19 @@ namespace MWGui virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); + virtual void startSelfEnchanting(MWWorld::Ptr soulgem); virtual void startTraining(MWWorld::Ptr actor); virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); + virtual void showSoulgemDialog (MWWorld::Ptr item); + virtual void changePointer (const std::string& name); virtual const Translation::Storage& getTranslationDataStorage() const; + void onSoulgemDialogButtonPressed (int button); + private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; @@ -271,6 +277,7 @@ namespace MWGui EnchantingDialog* mEnchantingDialog; TrainingWindow* mTrainingWindow; MerchantRepair* mMerchantRepair; + SoulgemDialog* mSoulgemDialog; Repair* mRepair; Translation::Storage& mTranslationDataStorage; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f49422747f..bd5367dad6 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -181,8 +181,7 @@ namespace MWInput break; case A_Activate: resetIdleTime(); - if( MWBase::Environment::get().getWindowManager()->isGuiMode() - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) { + if( MWBase::Environment::get().getWindowManager()->isGuiMode()) { // Pressing the activation key when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); } @@ -378,7 +377,7 @@ namespace MWInput void InputManager::changeInputMode(bool guiMode) { - // Are we in GUI mode now? + MWBase::Environment::get().getWindowManager()->setMouseVisible(guiMode); if(guiMode) { // Disable mouse look @@ -462,8 +461,7 @@ namespace MWInput bool InputManager::keyPressed( const OIS::KeyEvent &arg ) { if(arg.key == OIS::KC_RETURN - && MWBase::Environment::get().getWindowManager()->isGuiMode() - && MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_InterMessageBox ) + && MWBase::Environment::get().getWindowManager()->isGuiMode()) { // Pressing enter when a messagebox is prompting for "ok" will activate the ok button MWBase::Environment::get().getWindowManager()->enterPressed(); diff --git a/apps/openmw/mwworld/actionsoulgem.cpp b/apps/openmw/mwworld/actionsoulgem.cpp new file mode 100644 index 0000000000..6746f692f1 --- /dev/null +++ b/apps/openmw/mwworld/actionsoulgem.cpp @@ -0,0 +1,21 @@ +#include "actionsoulgem.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +namespace MWWorld +{ + +ActionSoulgem::ActionSoulgem(const Ptr &object) + : Action(false, object) +{ + +} + +void ActionSoulgem::executeImp(const Ptr &actor) +{ + MWBase::Environment::get().getWindowManager()->showSoulgemDialog(getTarget()); +} + + +} diff --git a/apps/openmw/mwworld/actionsoulgem.hpp b/apps/openmw/mwworld/actionsoulgem.hpp new file mode 100644 index 0000000000..0dd5266570 --- /dev/null +++ b/apps/openmw/mwworld/actionsoulgem.hpp @@ -0,0 +1,19 @@ +#ifndef GAME_MWWORLD_ACTIONSOULGEM_H +#define GAME_MWWORLD_ACTIONSOULGEM_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionSoulgem : public Action + { + virtual void executeImp (const MWWorld::Ptr& actor); + + public: + /// @param soulgem to use + ActionSoulgem (const Ptr& object); + }; +} + +#endif From a031c7761943afc38df5e0ea2a595a3cdcc4d90f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 15:56:14 +0100 Subject: [PATCH 0163/1537] Improved enchanting layout --- files/mygui/openmw_enchanting_dialog.layout | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 2549fd26f9..41b8ffa938 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -70,18 +70,18 @@ - + - + - + - - + + From 0079f62180afe7ddf2f9ec3f2d543bca07ee2891 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 16:27:06 +0100 Subject: [PATCH 0164/1537] Gold condition now always checks RefID instead of the name. This is necessary because in the french MW version, the sGold GMST is different from the name of the gold references. --- apps/openmw/mwclass/misc.cpp | 7 ++++- apps/openmw/mwworld/containerstore.cpp | 38 +++++++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index b971fa6f34..e4d7235cb7 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -158,7 +158,12 @@ namespace MWClass int count = ptr.getRefData().getCount(); - bool isGold = (ref->mBase->mName == store.get().find("sGold")->getString()); + bool isGold = Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); + if (isGold && ptr.getCellRef().mGoldValue != 1) count = ptr.getCellRef().mGoldValue; else if (isGold) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index e5b68841b8..a377f2bbbf 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -111,34 +111,28 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) // 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) == esmStore.get().find("sGold")->getString()) + if (Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100")) { - MWWorld::LiveCellRef *gold = - ptr.get(); + MWWorld::ManualRef ref(esmStore, "Gold_001"); - if (Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_001") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_005") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_010") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_025") - || Misc::StringUtils::ciEqual(gold->mRef.mRefID, "gold_100")) + int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); + + ref.getPtr().getRefData().setCount(count); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { - MWWorld::ManualRef ref(esmStore, "Gold_001"); - - int count = MWWorld::Class::get(ptr).getValue(ptr) * ptr.getRefData().getCount(); - - ref.getPtr().getRefData().setCount(count); - for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) + if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) { - if (Misc::StringUtils::ciEqual((*iter).get()->mRef.mRefID, "gold_001")) - { - (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); - flagAsModified(); - return iter; - } + (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); + flagAsModified(); + return iter; } - - return addImpl(ref.getPtr()); } + + return addImpl(ref.getPtr()); } // determine whether to stack or not From a723ad8f291c532bbb33fffb4193f44395d4c845 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 16:32:24 +0100 Subject: [PATCH 0165/1537] Don't allow toggling inventory or journal when a modal window is opened --- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f49422747f..013c722c02 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -623,6 +623,9 @@ namespace MWInput void InputManager::toggleInventory() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + bool gameMode = !mWindows.isGuiMode(); // Toggle between game mode and inventory mode @@ -660,6 +663,9 @@ namespace MWInput void InputManager::toggleJournal() { + if (MyGUI::InputManager::getInstance ().isModalAny()) + return; + // Toggle between game mode and journal mode bool gameMode = !mWindows.isGuiMode(); From 0f0cc0e3e301c73a80dbe446b31b4d68bd8d5602 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 18:29:21 +0100 Subject: [PATCH 0166/1537] Fix a few gold conditions that I missed, trade window was affected --- apps/openmw/mwclass/misc.cpp | 42 +++++++++++++++---------------- apps/openmw/mwgui/container.cpp | 4 +-- apps/openmw/mwgui/tradewindow.cpp | 5 +++- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index e4d7235cb7..c1639af2b6 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -23,6 +23,18 @@ #include +namespace +{ +bool isGold (const MWWorld::Ptr& ptr) +{ + return Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") + || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); +} +} + namespace MWClass { void Miscellaneous::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -109,25 +121,15 @@ namespace MWClass std::string Miscellaneous::getUpSoundId (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get().find("sGold")->getString()) - { + if (isGold(ptr)) return std::string("Item Gold Up"); - } return std::string("Item Misc Up"); } std::string Miscellaneous::getDownSoundId (const MWWorld::Ptr& ptr) const { - MWWorld::LiveCellRef *ref = - ptr.get(); - - if (ref->mBase->mName == MWBase::Environment::get().getWorld()->getStore().get().find("sGold")->getString()) - { + if (isGold(ptr)) return std::string("Item Gold Down"); - } return std::string("Item Misc Down"); } @@ -158,19 +160,15 @@ namespace MWClass int count = ptr.getRefData().getCount(); - bool isGold = Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_001") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_005") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_010") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_025") - || Misc::StringUtils::ciEqual(ptr.getCellRef().mRefID, "gold_100"); + bool gold = isGold(ptr); - if (isGold && ptr.getCellRef().mGoldValue != 1) + if (gold && ptr.getCellRef().mGoldValue != 1) count = ptr.getCellRef().mGoldValue; - else if (isGold) + else if (gold) count *= ref->mBase->mData.mValue; std::string countString; - if (!isGold) + if (!gold) countString = MWGui::ToolTips::getCountString(count); else // gold displays its count also if it's 1. countString = " (" + boost::lexical_cast(count) + ")"; @@ -186,7 +184,7 @@ namespace MWClass std::string text; - if (!isGold) + if (!gold) { text += "\n#{sWeight}: " + MWGui::ToolTips::toString(ref->mBase->mData.mWeight); text += MWGui::ToolTips::getValueString(getValue(ptr), "#{sValue}"); @@ -210,7 +208,7 @@ namespace MWClass const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - if (MWWorld::Class::get(ptr).getName(ptr) == store.get().find("sGold")->getString()) { + if (isGold(ptr)) { int goldAmount = ptr.getRefData().getCount(); std::string base = "Gold_001"; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 0a674ba82c..36e32c822d 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -144,9 +144,7 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) MWBase::Environment::get().getWorld()->getStore().get(); // the player is trying to sell an item, check if the merchant accepts it - // 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) == gmst.find("sGold")->getString()) + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f84a0abc88..f474f756df 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -135,7 +135,7 @@ namespace MWGui for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) { - if (MWWorld::Class::get(*it).getName(*it) == gmst.find("sGold")->getString()) + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) { goldFound = true; gold = *it; @@ -342,6 +342,9 @@ namespace MWGui bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) { + if (Misc::StringUtils::ciEqual(item.getCellRef().mRefID, "gold_001")) + return false; + int services = 0; if (mPtr.getTypeName() == typeid(ESM::NPC).name()) { From 7dbc779c3aa4b40e4efabe918cc285c587b5d522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sat, 30 Mar 2013 19:08:42 +0100 Subject: [PATCH 0167/1537] Self-enchanting mechanics --- apps/openmw/mwgui/enchantingdialog.cpp | 22 +++++++++-- apps/openmw/mwmechanics/enchanting.cpp | 55 ++++++++++++++++++++++++-- apps/openmw/mwmechanics/enchanting.hpp | 9 ++++- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index ef124bb430..7d5d1411f9 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -19,7 +19,6 @@ namespace MWGui : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) , EffectEditorBase(parWindowManager) , mItemSelectionDialog(NULL) - , mEnchanting(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) { getWidget(mName, "NameEdit"); getWidget(mCancelButton, "CancelButton"); @@ -87,6 +86,9 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(actor); + mPtr = actor; startEditing (); @@ -94,7 +96,14 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { - /// \todo + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + mEnchanting.setSelfEnchanting(true); + mEnchanting.setEnchanter(player); + + mPtr = player; + + startEditing(); } void EnchantingDialog::onReferenceUnavailable () @@ -264,8 +273,13 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - mEnchanting.create(); - mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + int result = mEnchanting.create(); + + if(result==1) + mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + else + mWindowManager.messageBox ("#{sNotifyMessage34}"); + mWindowManager.removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 4ef20a5e52..3590ae0f3f 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -3,10 +3,13 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" + +#include "creaturestats.hpp" +#include "npcstats.hpp" + namespace MWMechanics { - Enchanting::Enchanting(MWWorld::Ptr enchanter): - mEnchanter(enchanter), + Enchanting::Enchanting(): mEnchantType(0) {} @@ -45,11 +48,20 @@ namespace MWMechanics mSoulGemPtr=soulGem; } - void Enchanting::create() + int Enchanting::create() { - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + if(mSelfEnchanting) + { + if(getEnchantChance() (RAND_MAX)*100) + return 0; + + MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); + } + + mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { @@ -67,6 +79,7 @@ namespace MWMechanics MWWorld::Ptr result = mOldItemPtr; result.mPtr = newobjPtr.mPtr; MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); + return 1; } void Enchanting::nextEnchantType() @@ -110,6 +123,10 @@ namespace MWMechanics float cost = 0; std::vector mEffects = mEffectList.mList; int i=mEffects.size(); + + /* + Formula from http://www.uesp.net/wiki/Morrowind:Enchant + */ for (std::vector::const_iterator it = mEffects.begin(); it != mEffects.end(); ++it) { const ESM::MagicEffect* effect = store.get().find(it->mEffectID); @@ -164,4 +181,34 @@ namespace MWMechanics return true; return false; } + + void Enchanting::setSelfEnchanting(bool selfEnchanting) + { + mSelfEnchanting = selfEnchanting; + } + + void Enchanting::setEnchanter(MWWorld::Ptr enchanter) + { + mEnchanter = enchanter; + } + + float Enchanting::getEnchantChance() + { + /* + Formula from http://www.uesp.net/wiki/Morrowind:Enchant + */ + const CreatureStats& creatureStats = MWWorld::Class::get (mEnchanter).getCreatureStats (mEnchanter); + const NpcStats& npcStats = MWWorld::Class::get (mEnchanter).getNpcStats (mEnchanter); + + float chance1 = (npcStats.getSkill (ESM::Skill::Enchant).getModified() + + (0.25 * creatureStats.getAttribute (ESM::Attribute::Intelligence).getModified()) + + (0.125 * creatureStats.getAttribute (ESM::Attribute::Luck).getModified())); + + float chance2 = 2.5 * getEnchantCost(); + if(mEnchantType==3) + { + chance2 *= 2; + } + return (chance1-chance2); + } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 1daf34c6d1..fffa2c5b20 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -16,6 +16,8 @@ namespace MWMechanics const MWWorld::Ptr *mNewItemPtr; int mEnchantType; + bool mSelfEnchanting; + ESM::EffectList mEffectList; ESM::Enchantment mEnchantment; @@ -23,17 +25,20 @@ namespace MWMechanics std::string mObjectType; std::string mOldItemId; public: - Enchanting(MWWorld::Ptr enchanter); + Enchanting(); + void setEnchanter(MWWorld::Ptr enchanter); + void setSelfEnchanting(bool selfEnchanting); void setOldItem(MWWorld::Ptr oldItem); void setNewItemName(std::string s); void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); - void create(); + int create(); void nextEnchantType(); int getEnchantType(); int getEnchantCost(); int getMaxEnchantValue(); int getGemCharge(); + float getEnchantChance(); bool soulEmpty(); bool itemEmpty(); }; From ee5d0277e8729965bbce2efc0e9b4db3448e3cba Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 30 Mar 2013 22:18:34 +0400 Subject: [PATCH 0168/1537] fix for #634 --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index cd9908d3df..f7e9529568 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -198,7 +198,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c if (imData.mNumLongs) return select.selectCompare (locals.mLongs[i]); - i -= script->mData.mNumShorts; + i -= script->mData.mNumLongs; return select.selectCompare (locals.mFloats.at (i)); } From e27e53f607550f65c6b7b962fc5151f20b2d7101 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 30 Mar 2013 20:04:05 +0100 Subject: [PATCH 0169/1537] Fix not playable body parts appearing in the race selection menu. --- apps/esmtool/labels.cpp | 4 +- apps/openmw/mwgui/container.cpp | 3 - apps/openmw/mwgui/race.cpp | 138 ++++++++++++++++++++---------- apps/openmw/mwgui/race.hpp | 3 + apps/openmw/mwgui/tradewindow.cpp | 3 - components/esm/loadbody.hpp | 2 +- 6 files changed, 99 insertions(+), 54 deletions(-) diff --git a/apps/esmtool/labels.cpp b/apps/esmtool/labels.cpp index f08c31003c..3fb1166e8e 100644 --- a/apps/esmtool/labels.cpp +++ b/apps/esmtool/labels.cpp @@ -627,10 +627,10 @@ std::string bodyPartFlags(int flags) std::string properties = ""; if (flags == 0) properties += "[None] "; if (flags & ESM::BodyPart::BPF_Female) properties += "Female "; - if (flags & ESM::BodyPart::BPF_Playable) properties += "Playable "; + if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable "; int unused = (0xFFFFFFFF ^ (ESM::BodyPart::BPF_Female| - ESM::BodyPart::BPF_Playable)); + ESM::BodyPart::BPF_NotPlayable)); if (flags & unused) properties += "Invalid "; properties += str(boost::format("(0x%08X)") % flags); return properties; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 36e32c822d..7836fee16e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -140,9 +140,6 @@ void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) if (isInventory()) { - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - // the player is trying to sell an item, check if the merchant accepts it if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 1436995c53..be693eb2ba 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -19,6 +19,49 @@ using namespace MWGui; using namespace Widgets; +namespace +{ +int wrap(int index, int max) +{ + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; +} + +int countParts(const std::string &part, const std::string &race, bool male) +{ + /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string prefix = + "b_n_" + race + ((male) ? "_m_" : "_f_") + part; + + std::string suffix; + suffix.reserve(prefix.size() + 3); + + int count = -1; + do { + ++count; + suffix = "_" + (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + + if (count == 0 && part == "hair") { + count = -1; + do { + ++count; + suffix = (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + } + return count; +} +} + RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) : WindowModal("openmw_chargen_race.layout", parWindowManager) , mGenderIndex(0) @@ -144,45 +187,6 @@ void RaceDialog::setRaceId(const std::string &raceId) updateSpellPowers(); } -int wrap(int index, int max) -{ - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; -} - -int countParts(const std::string &part, const std::string &race, bool male) -{ - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - - if (count == 0 && part == "hair") { - count = -1; - do { - ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - } - return count; -} - void RaceDialog::close() { delete mPreview; @@ -229,28 +233,67 @@ void RaceDialog::onSelectNextGender(MyGUI::Widget*) void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + do + mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + while (!isFacePlayable()); updatePreview(); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + do + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + while (!isFacePlayable()); updatePreview(); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { - mHairIndex = wrap(mHairIndex - 1, mHairCount); + do + mHairIndex = wrap(mHairIndex - 1, mHairCount); + while (!isHairPlayable()); updatePreview(); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - mHairIndex = wrap(mHairIndex + 1, mHairCount); + do + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isHairPlayable()); updatePreview(); } +bool RaceDialog::isFacePlayable() +{ + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(prefix + "head_" + headIndex) == 0) + return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); +} + +bool RaceDialog::isHairPlayable() +{ + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + if (parts.search(prefix + "hair_" + hairIndex) == 0) + return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); +} + void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) @@ -273,11 +316,16 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) void RaceDialog::recountParts() { + mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); + mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + mFaceIndex = 0; mHairIndex = 0; - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + while (!isHairPlayable()) + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isFacePlayable()) + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); } // update widget content diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index efd08f4395..0ca440ad53 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -81,6 +81,9 @@ namespace MWGui void updatePreview(); void recountParts(); + bool isHairPlayable(); + bool isFacePlayable(); + MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; MyGUI::ScrollBar* mHeadRotate; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f474f756df..ab9f3a3101 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -129,9 +129,6 @@ namespace MWGui MWWorld::Ptr gold; MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) { diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c91bb40bf2..c467b36251 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -33,7 +33,7 @@ struct BodyPart enum Flags { BPF_Female = 1, - BPF_Playable = 2 + BPF_NotPlayable = 2 }; enum MeshType From c8606d2f63d63c8db1cca9838d2f03466587907f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 13:20:51 -0700 Subject: [PATCH 0170/1537] Implement IsWerewolf script function --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/statsextensions.cpp | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 0f07b4d2e8..7e9827062b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -316,5 +316,7 @@ op 0x20001f9: Drop, explicit reference op 0x20001fa: DropSoulGem op 0x20001fb: DropSoulGem, explicit reference op 0x20001fc: OnDeath +op 0x20001fd: IsWerewolf +op 0x20001fe: IsWerewolf, explicit reference -opcodes 0x20001fd-0x3ffffff unused +opcodes 0x20001ff-0x3ffffff unused diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index c5fc9436be..1d321fbbb7 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1046,6 +1046,18 @@ namespace MWScript } }; + template + class OpIsWerewolf : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + runtime.push(MWWorld::Class::get(ptr).getNpcStats(ptr).isWerewolf()); + } + }; + const int numberOfAttributes = 8; const int opcodeGetAttribute = 0x2000027; @@ -1137,6 +1149,9 @@ namespace MWScript const int opcodeOnDeath = 0x20001fc; + const int opcodeIsWerewolf = 0x20001fd; + const int opcodeIsWerewolfExplicit = 0x20001fe; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -1252,6 +1267,8 @@ namespace MWScript extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); extensions.registerFunction ("ondeath", 'l', "", opcodeOnDeath); + + extensions.registerFunction ("iswerewolf", 'l', "", opcodeIsWerewolf, opcodeIsWerewolfExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -1368,6 +1385,9 @@ namespace MWScript interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); interpreter.installSegment5 (opcodeOnDeath, new OpOnDeath); + + interpreter.installSegment5 (opcodeIsWerewolf, new OpIsWerewolf); + interpreter.installSegment5 (opcodeIsWerewolfExplicit, new OpIsWerewolf); } } } From 63af72c31577454322524c30982f964e4b6cfaa3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 17:31:16 -0700 Subject: [PATCH 0171/1537] Avoid converting to and from quaternions --- apps/openmw/mwrender/renderingmanager.cpp | 34 +++++++++-------------- apps/openmw/mwworld/worldimp.cpp | 4 ++- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1bab676c3c..7c442c6868 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -262,37 +262,29 @@ void RenderingManager::scaleObject (const MWWorld::Ptr& ptr, const Ogre::Vector3 ptr.getRefData().getBaseNode()->setScale(scale); } -bool RenderingManager::rotateObject( const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust) +bool RenderingManager::rotateObject(const MWWorld::Ptr &ptr, Ogre::Vector3 &rot, bool adjust) { bool isActive = ptr.getRefData().getBaseNode() != 0; bool isPlayer = isActive && ptr.getRefData().getHandle() == "player"; bool force = true; - + if (isPlayer) force = mPlayer->rotate(rot, adjust); - - MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); + MWWorld::Class::get(ptr).adjustRotation(ptr, rot.x, rot.y, rot.z); if (!isPlayer && isActive) { - Ogre::Quaternion xr(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yr(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zr(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); - - Ogre::Quaternion xref(Ogre::Radian(-ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::UNIT_X); - Ogre::Quaternion yref(Ogre::Radian(-ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::UNIT_Y); - Ogre::Quaternion zref(Ogre::Radian(-ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::UNIT_Z); - - Ogre::Quaternion newo = adjust ? (xr * yr * zr) * (xref*yref*zref) : xr * yr * zr; - - Ogre::Matrix3 mat; - newo.ToRotationMatrix(mat); - Ogre::Radian ax,ay,az; - mat.ToEulerAnglesXYZ(ax,ay,az); - rot.x = -ax.valueRadians(); - rot.y = -ay.valueRadians(); - rot.z = -az.valueRadians(); + if(adjust) + { + const float *objRot = ptr.getRefData().getPosition().rot; + rot.x += objRot[0]; + rot.y += objRot[1]; + rot.z += objRot[2]; + } + Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) * + Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * + Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z); ptr.getRefData().getBaseNode()->setOrientation(newo); } else if(isPlayer) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 75ff6ec830..209e4c4be6 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -816,7 +816,9 @@ namespace MWWorld { // rotate physically iff renderer confirm so float *objRot = ptr.getRefData().getPosition().rot; - objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; + objRot[0] = rot.x; + objRot[1] = rot.y; + objRot[2] = rot.z; if (ptr.getRefData().getBaseNode() != 0) { mPhysics->rotateObject(ptr); From af65ecd8415b3504c26b8d9fdb8d713bfef2fa89 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 18:37:40 -0700 Subject: [PATCH 0172/1537] Pass the movement vector in as a parameter to CharacterController::update --- apps/openmw/mwmechanics/activators.cpp | 5 ++++- apps/openmw/mwmechanics/actors.cpp | 3 ++- apps/openmw/mwmechanics/character.cpp | 6 +----- apps/openmw/mwmechanics/character.hpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index b67fcb2164..51fa55f4e4 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -56,7 +56,10 @@ void Activators::update(float duration, bool paused) if(!paused) { for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) - iter->second.update(duration); + { + Ogre::Vector3 movement(0.0f); + iter->second.update(duration, movement); + } } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 1480b3182e..a7615311b5 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -266,7 +266,8 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 movement = iter->second.update(duration); + Ogre::Vector3 movement(0.0f); + iter->second.update(duration, movement); mMovement.push_back(std::make_pair(iter->first, movement)); } MWBase::Environment::get().getWorld()->doPhysics(mMovement, duration); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 62958db8d4..5e112d54e5 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -168,10 +168,8 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -Ogre::Vector3 CharacterController::update(float duration) +void CharacterController::update(float duration, Ogre::Vector3 &movement) { - Ogre::Vector3 movement(0.0f); - float speed = 0.0f; if(!(getState() >= CharState_Death1)) { @@ -240,8 +238,6 @@ Ogre::Vector3 CharacterController::update(float duration) movement += mAnimation->runAnimation(duration); } mSkipAnim = false; - - return movement; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 46f0690e77..8cba49b5ff 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -87,7 +87,7 @@ public: void updatePtr(const MWWorld::Ptr &ptr); - Ogre::Vector3 update(float duration); + void update(float duration, Ogre::Vector3 &movement); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); From 0ce188b7cc02ef6e1cd49ceb8fd1b5e24cc1d48c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 30 Mar 2013 19:00:46 -0700 Subject: [PATCH 0173/1537] Store the position and rotation in MWMechanics::Movement --- apps/openmw/mwclass/npc.cpp | 9 ++------- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/movement.hpp | 11 +++++++---- apps/openmw/mwworld/player.cpp | 8 ++++---- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index a5319ada07..61d081b4b1 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -368,7 +368,7 @@ namespace MWClass moveSpeed = runSpeed; else moveSpeed = walkSpeed; - if(getMovementSettings(ptr).mLeftRight != 0 && getMovementSettings(ptr).mForwardBackward == 0) + if(getMovementSettings(ptr).mPosition[0] != 0 && getMovementSettings(ptr).mPosition[1] == 0) moveSpeed *= 0.75f; return moveSpeed; @@ -414,12 +414,7 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - Ogre::Vector3 vector; - vector.x = getMovementSettings(ptr).mLeftRight; - vector.y = getMovementSettings(ptr).mForwardBackward; - vector.z = getMovementSettings(ptr).mUpDown; - - return vector; + return Ogre::Vector3(getMovementSettings(ptr).mPosition); } bool Npc::isEssential (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 5e112d54e5..ea9ff7e10c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -175,12 +175,12 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) { const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWWorld::Class &cls = MWWorld::Class::get(mPtr); - const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); bool onground = world->isOnGround(mPtr); bool inwater = world->isSwimming(mPtr); bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); + const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); speed = cls.getSpeed(mPtr); /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except diff --git a/apps/openmw/mwmechanics/movement.hpp b/apps/openmw/mwmechanics/movement.hpp index 11eb83151e..6c9a4b7589 100644 --- a/apps/openmw/mwmechanics/movement.hpp +++ b/apps/openmw/mwmechanics/movement.hpp @@ -6,11 +6,14 @@ namespace MWMechanics /// Desired movement for an actor struct Movement { - 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; + float mPosition[3]; + float mRotation[3]; - Movement() : mLeftRight (0), mForwardBackward (0), mUpDown(0) {} + Movement() + { + mPosition[0] = mPosition[1] = mPosition[2] = 0.0f; + mRotation[0] = mRotation[1] = mRotation[2] = 0.0f; + } }; } diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 0dc8b37eff..b01b929c46 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -42,14 +42,14 @@ namespace MWWorld if (mAutoMove) value = 1; - MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[1] = value; } void Player::setLeftRight (int value) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get (ptr).getMovementSettings (ptr).mLeftRight = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[0] = value; } void Player::setForwardBackward (int value) @@ -61,14 +61,14 @@ namespace MWWorld if (mAutoMove) value = 1; - MWWorld::Class::get (ptr).getMovementSettings (ptr).mForwardBackward = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[1] = value; } void Player::setUpDown(int value) { MWWorld::Ptr ptr = getPlayer(); - MWWorld::Class::get (ptr).getMovementSettings (ptr).mUpDown = value; + MWWorld::Class::get (ptr).getMovementSettings (ptr).mPosition[2] = value; } void Player::setRunState(bool run) From 466c0086b84eaca4da61b8d3a64e9ba675ebe24a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 00:13:56 -0700 Subject: [PATCH 0174/1537] Use a full Movement to hand off to the world physics update --- apps/openmw/mwbase/world.hpp | 7 ++++++- apps/openmw/mwmechanics/activators.cpp | 4 +++- apps/openmw/mwmechanics/actors.cpp | 3 ++- apps/openmw/mwmechanics/actors.hpp | 1 + apps/openmw/mwmechanics/character.cpp | 17 +++++++++++------ apps/openmw/mwmechanics/character.hpp | 4 +++- apps/openmw/mwworld/worldimp.cpp | 5 +++-- 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 67d7dda6a6..8eea383eb4 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -44,6 +44,11 @@ namespace MWRender class Animation; } +namespace MWMechanics +{ + class Movement; +} + namespace MWWorld { class Fallback; @@ -54,7 +59,7 @@ namespace MWWorld class ESMStore; class RefData; - typedef std::vector > PtrMovementList; + typedef std::vector > PtrMovementList; } namespace MWBase diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp index 51fa55f4e4..cbc3802995 100644 --- a/apps/openmw/mwmechanics/activators.cpp +++ b/apps/openmw/mwmechanics/activators.cpp @@ -2,6 +2,8 @@ #include +#include "movement.hpp" + #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -57,7 +59,7 @@ void Activators::update(float duration, bool paused) { for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) { - Ogre::Vector3 movement(0.0f); + Movement movement; iter->second.update(duration, movement); } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index a7615311b5..6aae850878 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -17,6 +17,7 @@ #include "../mwbase/windowmanager.hpp" #include "creaturestats.hpp" +#include "movement.hpp" namespace MWMechanics { @@ -266,7 +267,7 @@ namespace MWMechanics for(PtrControllerMap::iterator iter(mActors.begin());iter != mActors.end();++iter) { - Ogre::Vector3 movement(0.0f); + Movement movement; iter->second.update(duration, movement); mMovement.push_back(std::make_pair(iter->first, movement)); } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index fc4af8dd63..aabd86dc7a 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -7,6 +7,7 @@ #include #include "character.hpp" +#include "movement.hpp" #include "../mwbase/world.hpp" namespace Ogre diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ea9ff7e10c..3bba065ff4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -21,6 +21,8 @@ #include +#include "movement.hpp" + #include "../mwrender/animation.hpp" #include "../mwbase/environment.hpp" @@ -168,7 +170,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) } -void CharacterController::update(float duration, Ogre::Vector3 &movement) +void CharacterController::update(float duration, Movement &movement) { float speed = 0.0f; if(!(getState() >= CharState_Death1)) @@ -190,14 +192,14 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) float x = cls.getJump(mPtr); if(vec.x == 0 && vec.y == 0) - movement.z += x*duration; + movement.mPosition[2] += x*duration; else { /* FIXME: this would be more correct if we were going into a jumping state, * rather than normal walking/idle states. */ //Ogre::Vector3 lat = Ogre::Vector3(vec.x, vec.y, 0.0f).normalisedCopy(); //movement += Ogre::Vector3(lat.x, lat.y, 1.0f) * x * 0.707f * duration; - movement.z += x * 0.707f * duration; + movement.mPosition[2] += x * 0.707f * duration; } //decrease fatigue by fFatigueJumpBase + (1 - normalizedEncumbrance) * fFatigueJumpMult; @@ -214,7 +216,7 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); // Apply any forward/backward movement manually - movement.y += vec.y * (speed*duration); + movement.mPosition[1] += vec.y * (speed*duration); } else if(vec.y != 0.0f && speed > 0.0f) { @@ -226,7 +228,7 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); // Apply any sideways movement manually - movement.x += vec.x * (speed*duration); + movement.mPosition[0] += vec.x * (speed*duration); } else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); @@ -235,7 +237,10 @@ void CharacterController::update(float duration, Ogre::Vector3 &movement) if(mAnimation && !mSkipAnim) { mAnimation->setSpeed(speed); - movement += mAnimation->runAnimation(duration); + Ogre::Vector3 moved = mAnimation->runAnimation(duration); + movement.mPosition[0] += moved.x; + movement.mPosition[1] += moved.y; + movement.mPosition[2] += moved.z; } mSkipAnim = false; } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8cba49b5ff..61efd0be0e 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -13,6 +13,8 @@ namespace MWRender namespace MWMechanics { +class Movement; + enum CharacterState { CharState_SpecialIdle, CharState_Idle, @@ -87,7 +89,7 @@ public: void updatePtr(const MWWorld::Ptr &ptr); - void update(float duration, Ogre::Vector3 &movement); + void update(float duration, Movement &movement); void playGroup(const std::string &groupname, int mode, int count); void skipAnim(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 209e4c4be6..37fa73279e 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -13,6 +13,7 @@ #include "../mwbase/scriptmanager.hpp" #include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwrender/sky.hpp" #include "../mwrender/player.hpp" @@ -875,13 +876,13 @@ namespace MWWorld player = iter; continue; } - Ogre::Vector3 vec = mPhysics->move(iter->first, iter->second, duration, + Ogre::Vector3 vec = mPhysics->move(iter->first, Ogre::Vector3(iter->second.mPosition), duration, !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { - Ogre::Vector3 vec = mPhysics->move(player->first, player->second, duration, + Ogre::Vector3 vec = mPhysics->move(player->first, Ogre::Vector3(player->second.mPosition), duration, !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } From faf293bd6d1f28827a6209fd63f63cba5d5aec29 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 31 Mar 2013 09:50:35 +0200 Subject: [PATCH 0175/1537] Removing old directory. --- files/opencs/scalable/Palette.svg | 569 ----- .../referenceable record type/.directory | 5 - .../referenceable record type/activator.svg | 1088 ---------- .../referenceable record type/apparatus.svg | 1058 --------- .../referenceable record type/book.svg | 692 ------ .../referenceable record type/container.svg | 1899 ----------------- .../referenceable record type/ingredient.svg | 1112 ---------- .../light source.svg | 1513 ------------- .../referenceable record type/light.svg | 1513 ------------- .../referenceable record type/potion.svg | 1161 ---------- .../referenceable record type/random item.svg | 1462 ------------- .../referenceable record type/random-item.svg | 1462 ------------- .../referenceable record type/repair.svg | 1280 ----------- .../referenceable record type/static.svg | 1141 ---------- .../referenceable record type/weapon.svg | 1206 ----------- .../scalable/referenceable-record/.directory | 5 - .../referenceable-record/activator.svg | 1088 ---------- .../referenceable-record/apparatus.svg | 1058 --------- .../scalable/referenceable-record/book.svg | 692 ------ .../referenceable-record/container.svg | 1899 ----------------- .../referenceable-record/ingredient.svg | 1112 ---------- .../scalable/referenceable-record/light.svg | 1513 ------------- .../referenceable-record/miscelanius.svg | 965 --------- .../referenceable-record/miscellaneous.svg | 692 ------ .../scalable/referenceable-record/potion.svg | 1161 ---------- .../referenceable-record/random-item.svg | 156 -- .../scalable/referenceable-record/repair.svg | 1280 ----------- .../scalable/referenceable-record/static.svg | 1141 ---------- .../scalable/referenceable-record/weapon.svg | 1206 ----------- files/opencs/scalable/status/.directory | 5 - files/opencs/scalable/status/added.svg | 969 --------- files/opencs/scalable/status/modified.svg | 1192 ----------- files/opencs/scalable/status/removed.svg | 969 --------- 33 files changed, 34264 deletions(-) delete mode 100644 files/opencs/scalable/Palette.svg delete mode 100644 files/opencs/scalable/referenceable record type/.directory delete mode 100644 files/opencs/scalable/referenceable record type/activator.svg delete mode 100644 files/opencs/scalable/referenceable record type/apparatus.svg delete mode 100644 files/opencs/scalable/referenceable record type/book.svg delete mode 100644 files/opencs/scalable/referenceable record type/container.svg delete mode 100644 files/opencs/scalable/referenceable record type/ingredient.svg delete mode 100644 files/opencs/scalable/referenceable record type/light source.svg delete mode 100644 files/opencs/scalable/referenceable record type/light.svg delete mode 100644 files/opencs/scalable/referenceable record type/potion.svg delete mode 100644 files/opencs/scalable/referenceable record type/random item.svg delete mode 100644 files/opencs/scalable/referenceable record type/random-item.svg delete mode 100644 files/opencs/scalable/referenceable record type/repair.svg delete mode 100644 files/opencs/scalable/referenceable record type/static.svg delete mode 100644 files/opencs/scalable/referenceable record type/weapon.svg delete mode 100644 files/opencs/scalable/referenceable-record/.directory delete mode 100644 files/opencs/scalable/referenceable-record/activator.svg delete mode 100644 files/opencs/scalable/referenceable-record/apparatus.svg delete mode 100644 files/opencs/scalable/referenceable-record/book.svg delete mode 100644 files/opencs/scalable/referenceable-record/container.svg delete mode 100644 files/opencs/scalable/referenceable-record/ingredient.svg delete mode 100644 files/opencs/scalable/referenceable-record/light.svg delete mode 100644 files/opencs/scalable/referenceable-record/miscelanius.svg delete mode 100644 files/opencs/scalable/referenceable-record/miscellaneous.svg delete mode 100644 files/opencs/scalable/referenceable-record/potion.svg delete mode 100644 files/opencs/scalable/referenceable-record/random-item.svg delete mode 100644 files/opencs/scalable/referenceable-record/repair.svg delete mode 100644 files/opencs/scalable/referenceable-record/static.svg delete mode 100644 files/opencs/scalable/referenceable-record/weapon.svg delete mode 100644 files/opencs/scalable/status/.directory delete mode 100644 files/opencs/scalable/status/added.svg delete mode 100644 files/opencs/scalable/status/modified.svg delete mode 100644 files/opencs/scalable/status/removed.svg diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg deleted file mode 100644 index f42475330d..0000000000 --- a/files/opencs/scalable/Palette.svg +++ /dev/null @@ -1,569 +0,0 @@ - - - - - - - image/svg+xml - - - - - - Tango Palette - - - Tuomas Kuosmanen - - - - - Garrett Le Sage -Kenneth Wimer -Jakub Steiner - - -http://www.tango-project.org/files/Tango-Palette.svg - - - unify - global - theme - color - palette - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/files/opencs/scalable/referenceable record type/.directory b/files/opencs/scalable/referenceable record type/.directory deleted file mode 100644 index e2d80ed58c..0000000000 --- a/files/opencs/scalable/referenceable record type/.directory +++ /dev/null @@ -1,5 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 -Version=3 -ViewMode=1 diff --git a/files/opencs/scalable/referenceable record type/activator.svg b/files/opencs/scalable/referenceable record type/activator.svg deleted file mode 100644 index 0c6db59a7d..0000000000 --- a/files/opencs/scalable/referenceable record type/activator.svg +++ /dev/null @@ -1,1088 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/apparatus.svg b/files/opencs/scalable/referenceable record type/apparatus.svg deleted file mode 100644 index 37cef0e890..0000000000 --- a/files/opencs/scalable/referenceable record type/apparatus.svg +++ /dev/null @@ -1,1058 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/book.svg b/files/opencs/scalable/referenceable record type/book.svg deleted file mode 100644 index 8c041a9e7a..0000000000 --- a/files/opencs/scalable/referenceable record type/book.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/container.svg b/files/opencs/scalable/referenceable record type/container.svg deleted file mode 100644 index 8c9465b668..0000000000 --- a/files/opencs/scalable/referenceable record type/container.svg +++ /dev/null @@ -1,1899 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/ingredient.svg b/files/opencs/scalable/referenceable record type/ingredient.svg deleted file mode 100644 index a77a9c8ee7..0000000000 --- a/files/opencs/scalable/referenceable record type/ingredient.svg +++ /dev/null @@ -1,1112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/light source.svg b/files/opencs/scalable/referenceable record type/light source.svg deleted file mode 100644 index f8f5066365..0000000000 --- a/files/opencs/scalable/referenceable record type/light source.svg +++ /dev/null @@ -1,1513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/light.svg b/files/opencs/scalable/referenceable record type/light.svg deleted file mode 100644 index f8f5066365..0000000000 --- a/files/opencs/scalable/referenceable record type/light.svg +++ /dev/null @@ -1,1513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/potion.svg b/files/opencs/scalable/referenceable record type/potion.svg deleted file mode 100644 index 552c14f19f..0000000000 --- a/files/opencs/scalable/referenceable record type/potion.svg +++ /dev/null @@ -1,1161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/random item.svg b/files/opencs/scalable/referenceable record type/random item.svg deleted file mode 100644 index 0c132ce958..0000000000 --- a/files/opencs/scalable/referenceable record type/random item.svg +++ /dev/null @@ -1,1462 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/random-item.svg b/files/opencs/scalable/referenceable record type/random-item.svg deleted file mode 100644 index 0c132ce958..0000000000 --- a/files/opencs/scalable/referenceable record type/random-item.svg +++ /dev/null @@ -1,1462 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/repair.svg b/files/opencs/scalable/referenceable record type/repair.svg deleted file mode 100644 index b1a23956e3..0000000000 --- a/files/opencs/scalable/referenceable record type/repair.svg +++ /dev/null @@ -1,1280 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/static.svg b/files/opencs/scalable/referenceable record type/static.svg deleted file mode 100644 index a6f29370f0..0000000000 --- a/files/opencs/scalable/referenceable record type/static.svg +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable record type/weapon.svg b/files/opencs/scalable/referenceable record type/weapon.svg deleted file mode 100644 index 2e832fff76..0000000000 --- a/files/opencs/scalable/referenceable record type/weapon.svg +++ /dev/null @@ -1,1206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory deleted file mode 100644 index e2d80ed58c..0000000000 --- a/files/opencs/scalable/referenceable-record/.directory +++ /dev/null @@ -1,5 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 -Version=3 -ViewMode=1 diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg deleted file mode 100644 index 0c6db59a7d..0000000000 --- a/files/opencs/scalable/referenceable-record/activator.svg +++ /dev/null @@ -1,1088 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/apparatus.svg b/files/opencs/scalable/referenceable-record/apparatus.svg deleted file mode 100644 index 37cef0e890..0000000000 --- a/files/opencs/scalable/referenceable-record/apparatus.svg +++ /dev/null @@ -1,1058 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/book.svg b/files/opencs/scalable/referenceable-record/book.svg deleted file mode 100644 index 8c041a9e7a..0000000000 --- a/files/opencs/scalable/referenceable-record/book.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/container.svg b/files/opencs/scalable/referenceable-record/container.svg deleted file mode 100644 index 8c9465b668..0000000000 --- a/files/opencs/scalable/referenceable-record/container.svg +++ /dev/null @@ -1,1899 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/ingredient.svg b/files/opencs/scalable/referenceable-record/ingredient.svg deleted file mode 100644 index a77a9c8ee7..0000000000 --- a/files/opencs/scalable/referenceable-record/ingredient.svg +++ /dev/null @@ -1,1112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/light.svg b/files/opencs/scalable/referenceable-record/light.svg deleted file mode 100644 index f8f5066365..0000000000 --- a/files/opencs/scalable/referenceable-record/light.svg +++ /dev/null @@ -1,1513 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/miscelanius.svg b/files/opencs/scalable/referenceable-record/miscelanius.svg deleted file mode 100644 index 96522048cb..0000000000 --- a/files/opencs/scalable/referenceable-record/miscelanius.svg +++ /dev/null @@ -1,965 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg deleted file mode 100644 index 8c041a9e7a..0000000000 --- a/files/opencs/scalable/referenceable-record/miscellaneous.svg +++ /dev/null @@ -1,692 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/potion.svg b/files/opencs/scalable/referenceable-record/potion.svg deleted file mode 100644 index 552c14f19f..0000000000 --- a/files/opencs/scalable/referenceable-record/potion.svg +++ /dev/null @@ -1,1161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg deleted file mode 100644 index d051ce049f..0000000000 --- a/files/opencs/scalable/referenceable-record/random-item.svg +++ /dev/null @@ -1,156 +0,0 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/repair.svg b/files/opencs/scalable/referenceable-record/repair.svg deleted file mode 100644 index b1a23956e3..0000000000 --- a/files/opencs/scalable/referenceable-record/repair.svg +++ /dev/null @@ -1,1280 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/static.svg b/files/opencs/scalable/referenceable-record/static.svg deleted file mode 100644 index a6f29370f0..0000000000 --- a/files/opencs/scalable/referenceable-record/static.svg +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/referenceable-record/weapon.svg b/files/opencs/scalable/referenceable-record/weapon.svg deleted file mode 100644 index 2e832fff76..0000000000 --- a/files/opencs/scalable/referenceable-record/weapon.svg +++ /dev/null @@ -1,1206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/status/.directory b/files/opencs/scalable/status/.directory deleted file mode 100644 index e2d80ed58c..0000000000 --- a/files/opencs/scalable/status/.directory +++ /dev/null @@ -1,5 +0,0 @@ -[Dolphin] -PreviewsShown=true -Timestamp=2013,3,21,10,19,49 -Version=3 -ViewMode=1 diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg deleted file mode 100644 index e0af57002a..0000000000 --- a/files/opencs/scalable/status/added.svg +++ /dev/null @@ -1,969 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg deleted file mode 100644 index e278ce596b..0000000000 --- a/files/opencs/scalable/status/modified.svg +++ /dev/null @@ -1,1192 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/files/opencs/scalable/status/removed.svg b/files/opencs/scalable/status/removed.svg deleted file mode 100644 index 17719cfc87..0000000000 --- a/files/opencs/scalable/status/removed.svg +++ /dev/null @@ -1,969 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - From 49b5b90cd55ecaf86945e2db0c23dc5a4f07056f Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 31 Mar 2013 10:13:01 +0200 Subject: [PATCH 0176/1537] png icons from nomadic and my rastered icons in raster folder. --- files/opencs/raster/.directory | 5 + files/opencs/raster/actinator.png | Bin 0 -> 2297 bytes files/opencs/raster/apparatus.png | Bin 0 -> 1864 bytes files/opencs/raster/armor.png | Bin 0 -> 1908 bytes files/opencs/raster/book.png | Bin 0 -> 1442 bytes files/opencs/raster/container.png | Bin 0 -> 1570 bytes files/opencs/raster/door.png | Bin 0 -> 1715 bytes files/opencs/raster/ingredient.png | Bin 0 -> 1624 bytes files/opencs/raster/light.png | Bin 0 -> 1069 bytes files/opencs/raster/miscellaneous.png | Bin 0 -> 1518 bytes files/opencs/raster/potion.png | Bin 0 -> 1876 bytes files/opencs/raster/random-item.png | Bin 0 -> 1612 bytes files/opencs/raster/repair.png | Bin 0 -> 1474 bytes files/opencs/raster/static.png | Bin 0 -> 1518 bytes files/opencs/raster/weapon.png | Bin 0 -> 1064 bytes files/opencs/scalable/Palette.svg | 569 +++++ .../scalable/referenceable-record/.directory | 5 + .../referenceable-record/activator.svg | 1088 ++++++++++ .../referenceable-record/apparatus.svg | 1058 +++++++++ .../scalable/referenceable-record/book.svg | 692 ++++++ .../referenceable-record/container.svg | 1899 +++++++++++++++++ .../referenceable-record/ingredient.svg | 1112 ++++++++++ .../scalable/referenceable-record/light.svg | 1513 +++++++++++++ .../referenceable-record/miscellaneous.svg | 965 +++++++++ .../scalable/referenceable-record/potion.svg | 1161 ++++++++++ .../referenceable-record/random-item.svg | 156 ++ .../scalable/referenceable-record/repair.svg | 1280 +++++++++++ .../scalable/referenceable-record/static.svg | 1141 ++++++++++ .../scalable/referenceable-record/weapon.svg | 1206 +++++++++++ files/opencs/scalable/status/.directory | 5 + files/opencs/scalable/status/added.svg | 969 +++++++++ files/opencs/scalable/status/modified.svg | 1192 +++++++++++ files/opencs/scalable/status/removed.svg | 969 +++++++++ 33 files changed, 16985 insertions(+) create mode 100644 files/opencs/raster/.directory create mode 100644 files/opencs/raster/actinator.png create mode 100644 files/opencs/raster/apparatus.png create mode 100644 files/opencs/raster/armor.png create mode 100644 files/opencs/raster/book.png create mode 100644 files/opencs/raster/container.png create mode 100644 files/opencs/raster/door.png create mode 100644 files/opencs/raster/ingredient.png create mode 100644 files/opencs/raster/light.png create mode 100644 files/opencs/raster/miscellaneous.png create mode 100644 files/opencs/raster/potion.png create mode 100644 files/opencs/raster/random-item.png create mode 100644 files/opencs/raster/repair.png create mode 100644 files/opencs/raster/static.png create mode 100644 files/opencs/raster/weapon.png create mode 100644 files/opencs/scalable/Palette.svg create mode 100644 files/opencs/scalable/referenceable-record/.directory create mode 100644 files/opencs/scalable/referenceable-record/activator.svg create mode 100644 files/opencs/scalable/referenceable-record/apparatus.svg create mode 100644 files/opencs/scalable/referenceable-record/book.svg create mode 100644 files/opencs/scalable/referenceable-record/container.svg create mode 100644 files/opencs/scalable/referenceable-record/ingredient.svg create mode 100644 files/opencs/scalable/referenceable-record/light.svg create mode 100644 files/opencs/scalable/referenceable-record/miscellaneous.svg create mode 100644 files/opencs/scalable/referenceable-record/potion.svg create mode 100644 files/opencs/scalable/referenceable-record/random-item.svg create mode 100644 files/opencs/scalable/referenceable-record/repair.svg create mode 100644 files/opencs/scalable/referenceable-record/static.svg create mode 100644 files/opencs/scalable/referenceable-record/weapon.svg create mode 100644 files/opencs/scalable/status/.directory create mode 100644 files/opencs/scalable/status/added.svg create mode 100644 files/opencs/scalable/status/modified.svg create mode 100644 files/opencs/scalable/status/removed.svg diff --git a/files/opencs/raster/.directory b/files/opencs/raster/.directory new file mode 100644 index 0000000000..7a78deef5b --- /dev/null +++ b/files/opencs/raster/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,31,10,12,5 +Version=3 +ViewMode=1 diff --git a/files/opencs/raster/actinator.png b/files/opencs/raster/actinator.png new file mode 100644 index 0000000000000000000000000000000000000000..0446af22cf7d4238e06d7682ab5ec86127b103c8 GIT binary patch literal 2297 zcmZ{lX*ARi7sr2+b!?S2`22n@r05bxw9> z^a&3Bmx+@u2Id9;@G%8)gk@vqEIv0)41tP1iIu;TIOI)p00=$@0Fguh_{}UuE(3rc z2mq^20HB=-03u$wjn;5xgZ;jl34%$c9T+u5Fu~=8wDV!EKK$z}kN}Mw0O06FAq;FW zly$VLSNgD6cnjljqh$tyiWEP+dLoMS><*1|p{VYgzjG-~6k=+-Tw27pJha7ule}iJ zCjHo-@1Xm~92G#P9X3(>6-s7(vyD7E^(R zY|+H&S)R1roK?+@EQ}5zxj=k?*TJtLS8B4(0LhYFtdwhEGFBDkQ_??mI8^AuH!gID4Sc&3jLI6eP)tANo{PpG~ zaSm&o4Q=0&PfBZ$R67^YrGvI?xmQh7k17<5#{Iyk(x-J43&iRoQPZs6|=c~?~hpWO<)=%C!K4rHq0*w?(Z zOC7`(HWg9=q|J4gPT|rJLH50I$Zb{m>(J6qH** z;dZl6nk-)HhLtzN`6@^G<#C2L5n2$7PHJ~2W*Llvw0!=N3Xu)rCJ08YJdw$~&q&n8!U7?6S7tH0Um~iLog$FC%$~rzyzd zvfo@`qXO`LBSGVy1fHixQF0gKQWA`A32wqu($dlna2G#U{+w+3Gq%HBBl(zo13KOf z-l!a1;>{F0!(a^q%~^@37a&2P)2x5U9HHq{5;3eeD+()`F}UbtW=56ai4&d2AiepB z0wfp*>a=P(j4yAAP{>$tIkrk|l;De4)8qFz(Q@?cc)uh-_?hU{LPXkv(j{s%c6C{L zIR?AjlX|22uF3}(;Pc|wj0|D=?=wHA#-~&t4V8|3CJ3dl%myEZyjlBQ+g`Xb z;3p||IVMz>-}HQ`Lu6ZGDuU~^h_-l8o=9|iTO2|z%dF(v;cE+%hIucUFb$8ron7f$ z5~lHmP`>0ve|NWu@53V#4+Jkpka>lkP8py7A|4y%eg!h9Ua-cl?9l9-do5%mzS^bF z1C8d5eJqpnMK((!5^oJkOpf|*ZhD4Pgktlw2;QqSh?}%JPxWwN-IuMS|CB^n2h7Cp z_RnlIe0#S(-Smh4XGdaiY{)ABwbH{Mde5LDG*b*3jK=LyH9C*t;xzfVQ@FPv-tI1rlDjxq?EYBlwLw^!DnfrR@Cm1rW$W&R2uH zttxR3)!8%fUyoNlrYE|+g0B*SHCvnK(~IZ0>vcJ99R)9Pbk!=LWFw=BT^W2`26E3u z4GTb+=~JG;p}>3kGNR=`U*p);x$u7SzN{B|&UTv!R-76axHpn}NnkM0Q?fX+!N&7}ZvfUC4+I1RD7!v(^TA=g@XDUvE;$?Uv& literal 0 HcmV?d00001 diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png new file mode 100644 index 0000000000000000000000000000000000000000..613030267620c5a7680dec1cacb012a6cdc7e5d7 GIT binary patch literal 1864 zcmZ{lc{CgN7RP^)Al9ZELQ85Wu{C7I2nLBvZ7mu~rJV|~Or=I-jCB(E+H08nyr zB$6aV9VA>vQX}Hx)+B%hMd#GM8pDFuLS z$tY2sr%KNj2-yEq^C+a`W zlh;kxakouF;g{19A!aZmruY=!-+ffy&ye{6)u7HoG9AFdRm%j2aDAN<{fYc z9j2o`dSul)mp};%bH7pTc~i?aJm9x0M%;`10Pbe0>Q(V17jm^?Aew{2Z9U>~R{N+t zb*;B?WP3wtW8KH3Y=Yebaj;?%bF$#`vwOOC>s3Y>jOE=5kA(`Mus^@EBjL4XlBjri zbMjvGpo#BZkFTCy{XemMv5i>?-CJBD>qZkh<7wl`9wdU)&kf|5h3zO_Q|#&^foti_ z-SFGHXK0YQPia3`MW0ae^8QRyvOVr0&mDY6ws(@#g`r>t$V_-1yhBY5O?5fSP$@j` z*S2&E*e+@`H;^N2E#e!(w?r44;#W^wv$B`Js_CN{xkm`h;RJ2sAVD7Dr&xg8x}xk> zVv#(ZWqmhQDAbsLGMNZwH8L8_-Emv(N5eX^sAVJVy%p#>Z!Z)JW~I6buxd%!M>3Jl zXwQZlZJ&N(hyA>tkOaq9N^2K#&LmmA$U_=Eu_LM(DP=a~E>&|O%33!69_{#|0i(Q-KHBm&D5q=2{bQZn z$oZn|F2Uzuvs<%++KN&s-QDn9iU8px2jJdb52F_|xR8d~)whD$5qx+RwGtsk_|uhN zKAlPe*npuz$3hPsU2U3x7yG%jmMl1*s`AJuoU?0c|%FcRQ`RyLWctGI_r&Gzs-US)rNUmpr{a`jGT` z+Rh-?;#9p%`InwD1^?Jv{bZ^MFJ`Z4o(;oI>>CwG<78>Zv-9gTm-W}eugQ+D9t$gm zu+QoXcu}-B$kq2}r|1wk+BT=;I$muhJ|aR@^hfA^1*fi^k{Rl(taX|o^8BZuxbOjU zuHrA%GctFeo|OX+Rs0zd$`_86jfC`aY)o%uyx_bG`PK-*+foDAdj)toJ9Wp_?x5pI zISK7n;G3BhESH3H*5siS_jhZbmu{>UeLvK&FeZ$GF`J1ff!*L;CeSWdHceXLGvAYk zLVo>~y(1<5I~h7K)!e*^j(yI!0P`<_|2b15D*541`BRTV++jZ1g4WU(HEWd(evjW& zhO-j(SDs?y?7^uSo31O7eJyHGnz6x~sdW3cHs8mjXfwB3x07LAJ}u+4YslMLmkple z@EdD2q#P-#Si@*#lab-S;!xiD{6+QWKBPF`BOj&-AN98U`@4^)3qpeX6ssqoJ^PWw zfZ}^KDmkX&wK9A4uCrs0VxPl0BDu8@blhW`lhCaumFC)c$Xr@i*HD(t?ozex5)Ph> zdQcU{=G1cP)(ST6ycw@|Tc9fwn660X98Vboy^u0ar8a%MexE&&z}_}mYAbh2EQ0I} zE4{e?f`K326IRZJ!-h^GEHGOMIUa8;9^%SMlHW;Mxx1rF# z1I-NNr80lv2j=I?x}>MSaEekB_DK4$=SH`He*W0wa-O-u)3BkK8 zJ6Wk!AsG$CGi}#vm~{N^Z!WvtS_di?+@f)CI}uom>U7H2D7liyp&R+*rN{uk$UsYK zc%THp3}cEl#$b)HrkndGfNCc+$wJWAH$8%fNMdq|KE^SY8N9hAP+8h rga$>@{lWtQolZBoc9RxC^$QC$2@MY}TC`S|h=9|NuEZ(=Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000K#NklE*K}A7_D%3jer7Qv#!7?%mg3)T9 zzUR&m!LTI#gPD*w$?rMOIrp4%*8x~3vA3^Eh>u5nTpZ$JV-Xt@gXrjJL`6j*GBOeo z5fKOv4@X#77(zos5fT!D;NV~=l}ZE!1wj!Qh`@jV_;`E6*kTX(;&|{xu`srYhLJE5 zhQe?dSchV>RWLSL24SN`AT}9V4ibCaf`H4HFQdD=8`rK~!_})-(b?IFOP4O8qoV^C zE?huMOAF4OJBQ}xW}G>52B%M-MtyxfYHMpzQ&WS=%1T(<%HbT;4JTy}928xU1YCxl ze>+6JEfC6^V70daf?cOz=w6OZTNVkhx3jCdc<~}0K75ELPoA*9(a}+ijErD-co+i% z1L*JX$D>D&@ZiA%+`D%VckbN5?c29;>((vw_Vz;R9*U?VF7!`EyK7O+g;GAH`?i;JZ%XMB6_oYE~n+ZVov=y~J1F zPGeu$6cP$2pv)S8RMCu0PPy1eVYed-e?X@84e%WnW((Zrr$m zo}M0DzkZ#i>&lfY*t*>po-w@$I5Y{r^e0@T!|+P$$DWk?*q!)0cE;a?N6d9>i{d^T z-od4$0S4wCFy;x`G&NvnYg={x{CQ?6ML97sp%XkbIvYD8ujveT32A|;V+xd^F)%YV ztIJvnRSHFLG)hWJkd~IFEugWnk>!{Qi%!5w@bZf9A>DIA zZ@BArA5>ISps1(_si~D*F?e}- zIaDeYl9Q8R!smZT0STz9t7FwoCtzr3NUPc#8qYDfU;4OC)lLOx=UW4zRIY)Sm6ahs zKOc#SiAx2DI04kr=x9w&PO`?c_^43_l(@(02lx9K#sY^W@Y2#!}d z5#Z|Ll9-*H4eEx2gM%0w8)IS!?z$reUa5cT1vj?di+okF7QC>q5LsDSkjv$;FgH)s z^np*;uU}77jRwr!yLVY3(m-}BD{jvZr1(9yv`O-zjd zdg1KkG*(?*&8(+1_y?uHBcfX`IA5B$Dm*VQkJ)c75R4IXi2ye@w;HNY>WG;+1xQj2 z=?9m@A~Z5-#mEVsk&yv^e}7n7Sk!036Mx68vByf?UH{+-m5}crMqd3KRE_g1PBjhOvjCo65o^M! z$Q23&4WSzg(Q64X7jBjDY$Dhu6PPiC!X`Chavy7rR1JLRafl`EYr+p7K8!eS-Ltp1 zR|^CJ;}r$a14C1nS&N;gu$`On$;E#m`^OiYfL}H9d;u=@{sAJ#y*k0u)6)^a?TjBs zujK%}A+U0h8JK(hYay$LEa^9VSuus=l5w_7EQa$fU3G%zs~vP6bD{6Fey?37(#w z)cI-`Td#ErK7P2tQ2c(2YY``+0p9!j5R*U7Inu+e+TJ?DY4Py$^CS4ga_|)$pa*<& zsq71$E4RUxaC=-G_NMm2(kU9Mf?}N_r@Yg>for+5T<*23U(*3rkS2CbpYuJi!6^@X zNhFS+_=astZEbCAu&iWzW@aY4#BdGg4Yzu+p0Bq93t!l5WYziEW-G}3!x)ejmzy_l zvWpAV!N)nL$O-Q3>^#piHa@f(eAN^z{vx-%s2m*~)wD`cyQY~zH>j?zE}T4hQd4jX zwo~M~z;zZtAGEfzO61z;4BZ#0rxz3yXs&5g?I|fKtl)&!)-!9_zG@>{%`)zX#hj2y z8Yr|@QG2C)lPH-?2JW0s8W|ah*RuV83!pD@L+cYWGqWzKRH~+2(@mMXS*f`+bLX`Bp?o`MC0000N4M86b>u62;YJ)%L!B43 z$qR^=l~sJ*BJDR>qkY&z`x(M{d3jr^kA6JuRN|Uo!nZ6xhxW*TYs4Y16CV@$o?~R? zBJ$%OWCB@{eDMr}gb>CqLjxm`bMLiVE6>6L17lf>hR(UHYoKS8@ERb$1r3tg z<6UGCO1xVW)HnB*>yC|RlMnmWouPDq`G50ip#OsU+G>(1g8IKNPQW{8=`pC7C z<^4In6h7f^ z^x}B(RGg-6=Cq#FCfvN-%FeP1b@cUI^>BFHDZGLH_qdaI9L~FTmHHpUrBF(6VC4TBPR!YNK?bFR r1eegjaE2c}05BK~-Qde1VPrpQfNm%~D0kUJ84>|IYm!xkg)j48+bVhF literal 0 HcmV?d00001 diff --git a/files/opencs/raster/container.png b/files/opencs/raster/container.png new file mode 100644 index 0000000000000000000000000000000000000000..7874606ab9b905dd3afc5e58b929e586241f3fd5 GIT binary patch literal 1570 zcmV+-2Hp9IP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000G%Nklonjx#Q!6{gxwt>Qc} zb!j`T9sLEhJ-wG1I*QqVAHJX7yZ4;$eBV9ay<-53@fL+fHa*KA>T^Uh{2UTxQ4Bvj zQplH*C@~57Vxy2RiV*UJBnrZXd>)CJ1|gpm!uF+wGU>kd_XtG!kF5C78H*pPW6)h?!S!WkTwNNCON*m$aX}=`&o|-Bya?>imm^WbUKuq3nN*ss zm2*#9vN+scnSj6AO7X|85iz=Ll({v0=1JxPzP~O>Do~f z7~G&Bf^pHzA2#RW?z(i3nV)ooBR!OH`2rsN?z03Wi?JDDqTQ?Q(ic?rN38|;sV>>A z>=gW1nE{Jq#V-=n>~6Z&7ZHyH=;BnJ_(E}%`1#S)>r!Dr~XKD1mOj3FMKErwvCl zzg24+75J`cN^H+iz^W9wJsEBlpbke(hBn-AYCbgcLGTtkF(qXH@3#V_CgEf1aMWbJ zueQG7a6`M@lkBg9H%|#hykZyxY*F05H})ps_Z|nj52WGZ&IFumjmPQcI2_v;i>?L> z4y}*I!B3;mQ5T8!8Y8}RMqpQ!0oy9|*s@56rum_0bcCROwi;`TRR~iA{^Pd-`T818H;j_DlMeSrR) zq+uMj@eB?YhvC%1NPI!0r&Em%7GE`|vQzL63<1av8V8*uz%gtB^cqzh&h&phLxW=# z#Org^!v=p}CqSHZV*iM)WR!7&is{{vA;*z&J=$k#hLt%5UlcMC+CX8iw~MLQTd`Te zUimyJ5c`X?=qL>FdemN*oq{jbPQontSg0lJh0zeG|IjQ%+jJG_1&zmZ?hbsBW+J9? zW1$LU+};KKdKXah$kzp6Yg#b&7pkx+MfR4-cmiLbngFwSf=2`Livay8MlN)1n9PwL zP++TF`i8@K19!;BK`jpO`9kvfGBO6US87QahT5w)@CwCv%#^$Xg_s%rPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000IeNkl|Rc-r7L=Ih;te9|F4 zjY{HX#4bDt*#ueb-{YTC1+LR---$@#qt<}w<;f-q>)jrF)aS>QULP*^c(I=I;@lwz zrc)L)xWt!!tNs!Hjv6BS5~y(*M#GZ$e7V(uTf-sTn@-@XsW`rzjNyxkC_W#H;?8IU zpN@p_$$KGuko90ZVS?A9e_kyMx&27&Nr1trUU8QUS^&Q~6vAA_jlmij11TBPX&2T> zky}SXxH%NWwE;g)Hrf!j>0gDd`q8~e>`H+Bu67z;Z1nkXeHe67JPmJm z&fxb*iGu&HgWntu;>J)w>AuNt#!82a2GoP)Rv8Tr9sFi(x)_O~1VVQ4;R+31!E=^< zug-UZUmfsajcjNQS!g>vxRj+?2@7xXKew@o~eeWgvPH^sgwo$@#gM^EnPR!Mq z5j1P_sukdbyFM6D_WVqjUm;NnILpr9)Ae?o?{H!!Wg-Gq>IrbX^6qoUEO+^cgztaT z{<`M{*$bYt>{A3jS!c&;J0)bb5dl*P1nP(Y$15k?=}s?BcX_v0O%3=3l6|7ihKX7m z&K{C6nKZ&*3V~XeA%BVTp7(pH!=n`Mxms}Udc4MpkwzK4H4?H(N=3W=57jeJ>lE{A zU2Y}Y7u!8(4qDKgw4*0sLoRMZHf}|C%!;n46`c`_QXOG4+Cyfv1x+{Xf@Q;FA|p7W{|{63>}ZO2lx4U1_jy#=f|95tacOv6aT>Ro!cMUDC`NJv6{ zIU_3rcdXfgqg17UFVtHw5H%7BBaYXb(eKy7DQMIuVM5a9ms%uc+K;AX%r(i%RpW%) zuX6^UuOrZ~fk+rIUu#0Ij|k{1)Dwu?_4&oLU0F2-=fhG8_))rkeIb!Zh~V!YZxtM+ z5Qq_hQ%yES_QF+D+c^WyrHtqy0!)Ixvz|)Gx)KzK*>rh+&lRp3AC|oat{{5>e5Trf zTtHAr@OQUM14&!1-hwC*SZJ^+vhzvh!@}uSY}$)~PbEZj`}N2L1xzPJbUI5U5V7j= z^E6BxuY6MZu#^Hm5f{+q(;-VFCgUPH92Kx@%hW3nwrcaoXp%YG`J|4ftZ(f3Zk;pu zSX7S=k4{lxA|{|sE{CnE6ap4)o}W?d`|&0_S}EbSQ_f2%=Mm9F)#&CD=-)8`^-ewN zsA}m2Tq9FSIt&K&3Yk`^4A#mL2!x0LKcm?9Lbji7vEzMCx~8q9JJDcKLWcKz=kT%T zEIW73;G+>8GPV*4@B?xzCSrj=cox`>IRcucmEz~sRMLP68nkf&8I1}UiRf`8tiw=< zx(;YD;IBfTuM)l9O61%c)EnQ0MN@(THc|U5Y_39xDrl-i&{&B8mEWL&Pt?Fm8DyqtZuu)kx2O(Bzo)vo${RhGC1icE4k}LoK002ov JPDHLkV1nG+EI$AM literal 0 HcmV?d00001 diff --git a/files/opencs/raster/ingredient.png b/files/opencs/raster/ingredient.png new file mode 100644 index 0000000000000000000000000000000000000000..6f9a09d2e93d64c118e7d375868068f77a2b0d02 GIT binary patch literal 1624 zcmZ`&2~bmK5PpP2EJtOSS}CGKZAHsv$N@<}5J(`91VR$7@t7c@bqW$lLI|lEA_#>0 z%1Iz7cpyg;4oO5gRJ1xe9)+TCq7m zwl2011UW>Ki45S~mYS0r2nq;V!>KpM20{?5mQH1n008;`iNz3CiRLNLISn|G z7B6Z7hrp@x<*BfO2He5sK*_1#vTkyDZxlz4-m63lwK!>4gmQ=hV0e2^hfV}%<3lCFsSGa;a*><0hx-bm%}aynOuDeNRx_EA6;&;y7Rb&|MB z6zH?8J5qEEFVx~elUWK3M}|7u7J8^TP%PdisP`-BBG;UY7HIr)8gZ3psRx?_07J!D zic}Y#DMw}3V*y6o>Ip310koMi6kqKJ$Pc#!a#ffQA9XZAP^QdRd}6Cei{mPmgCGJ3 zbDNg&K^5?dZv3Y)F)q-xky+VCRSh$%4K&3NLo*UzcY$8p zA5+>z)?7)bABit$3p?5orW|H~Im!lNmBY-^?nuQDQ>rJ+2V=q1r1}W($#v)H@_|^O zcC|6O_B_4jTucoh>0TDUSQlPxq*WPcg`K1-BMtOpZsPmYYmwBD{Xltk|%3{zjF_{C>0bnla1I&cm3=@jk8Cs>|yB{3i@piO&Dm=YBwc<2o)jLk-_CN4mpVneqbiS8q<8pS(r>ABnr_}@O$qk3B((Xt?hc}eSy>=RT_p)NW?(Cj&@{~!2 zuC1<4eB9EU>UM{c&@QVBlh-BCcUaf$GG^(jQO160s|z)E_CB97ioNw1+wAb4zoe~oOoJa8{VgxwfROgLjP8by z>o~9H(#QO+F7##x2!@8P(LBY26IMxi$M1&X#?L!Z@yEv>>62Hv&Le6%4qRP$zJ9G6 z`{9LyOKd@oAVc+5v>V>->Ce__c0Sm8o=#a}FPPmX@{4QSk8gVPoulbA`)2nn+8H@Wt$gpbB9Q&2 zg~D}yAu+sk!$7dN!NDZat36-^Hu6Y`ygkXhR65KM8qP@|+EMFu6=|{j~ zJdr2@5~+5&Vfj}=dd8mpdxig>Fc-rQ1qoj*S72uBnf7!9< zX67ZO3laK!FGA{SgzOknTM#NI5L(Jbh}Dcxu%fk3!p3>0#c5JLCV*$G&A`J>Sk(ip z0a(FifR&qYzZU-d3G6dqv$|OhBdlv+=Cn)yDg0g!Py4`z`Kw@CfM*l1(gixTYx+1m zYKM(6fCaEGf^8BWUvipME?qe+o`;Q50E@en%?PX4T&4=wOc^Y7fn5*li*Eesgv(In z(jSAhL9j2uXpCi;GdGa6G?;B2=Q*aiaFg@oF55a52P3hL-#CtGKHTGw`ZV}QtqsdT z2wSY&@tnn>XFd;l_HJCuCG{dOBzridPDC1I&bcp~mL})?m!zr4sZH@5!5=x~Y^lrA z=$u!B;jjmEnu?vX%D-mM-e?QIawfj-T=>FJ;@!)vJ6*Bk-Avup1X7nm8s8^p%N^z# z(tM13P(bR1H9R&`j&@@Au`*qhfzYNM3A=n~(eF)`vx6vvtd|@p zX3=PT^}=$4c$?3`uO2zhNVa=LeQ35HkN4dYKW0eXMr~a-_ry_#N$dmCvs6EnDt$AhnzVzpGT5#AN?`HAdx14FXFXe+&0T0zucP8QB zB}Gzp8UBm-rRWZdk1DzagO8JWTq*NTUas2f;EUJQb>G)C(ND4Cyx$Ct^$QnOBvewk zyJZ2Ah$FPY&^J0t+vWN5ihT`PV(FOVkR(&n!O1z0v0rdlkmYyr^>w;$*|*;a6^>g| zY+rOW%^Y&#lECoqP6C5 z`h$ACdSCHZ47c@bG@7lQ{XQeBLl^powOYT4@1T~T6AXoawUItR*!+*w`__z{ z9C$YCPYq~P6beqv{TM(A*!pVl`G)4|m){;`F!qgbo6dfBuCXrgvuwS82!fbO%gMG( zE7l#Vozo?+% z{}a-fl^Zx=ySqb1Nr6%&E0rUaN)=Z0NpV@8Od$^|DJ^VSW`|%BO6H4r-HEwXe*-X~ B{}liL literal 0 HcmV?d00001 diff --git a/files/opencs/raster/miscellaneous.png b/files/opencs/raster/miscellaneous.png new file mode 100644 index 0000000000000000000000000000000000000000..b6cb250400cb65c921d4ecbeb3ed0ec5cd0ec014 GIT binary patch literal 1518 zcmZ{kdpHw%7{`C3&1Jddek~#CqUJIQhh%Px+(taeT*hW&%Wdl67?o1F9nNGVj!QZ@ zN_E1BNlF}>xrIeTb2}14TIqD=&-2H5pXYr)&wKek-~Zlhud^<4vRbkL068~Tl#iHt zJ1Gql*Mv)#HpJK!?cm`6Kw}G=Tk!%Ge#QkQrZ_~7t?6ROP+S8O#Ma+-5(1|pOT~8WZYT## zK-Y762ua0H<#qZNdztM{ZTk56GF=Vd`O*m8=;T@lOH+Jr;jJIDx+jNmeT=% z!;SfH>?Y*=#+xyG1tdZx(?MiBY3u+!B*fX%vtnCu)a0lJ1>UQq@n@}qS;NA~@dS?O z2fJnKuiT1Le^2pwCN%*cYnS~vE4a3SFQg&az&4_8Qsb2=B)vL$qt-%UdqtNS0s?!& zIaR&+0k!fkyy4_?ZCKig_L&rJzVbt1a8^eW^V2TcdHks*X0fo|X8%vuZnzgs0(_fhCM^Kk=0S6 zz{boE0?5rGY>@B4@Ar6w{X|Si@m@Wvl#Gy@S|@KWuG@ayH`O`PZfVK62rt4m3KyjC zD<1-$rIQT~(TMXWdGFqEN$F&pTAyt#Ld|rg?zX8m>xX<;s5bn{Oj*&pyJTonqSv&# zSM{!LQ9Y+T6BZ0p8T+n#HP4u)I1Hye_0~VgTNB6)@X)R@>?7I73d^o{;~C0eSH|t2 zTcN%ffm{Xr=(Oqn159Zpb&2%KnS$iK?l~89GVl}ZW<|`L93LISNJiA#Za6DTIi-`2 z)IiNJe=NLMQ<>?=`T(KC889eA>p86B)~v$n>fRqZD9frtc@R)J*nvzM)Fwm=>cOm? zzoAa9q&xQnRmmyBtsV4MotB0{Fj0aVF-XTUc|>Z)H~q<@i&tFo61k66A91PO}5~Ma%)#AX^iyCg>7p-L`F}33|5ZJ zyQ6)4$j)zY%GtSBUD0l&>x}Ly^pwA&@ZfJRth{4?MRhUGD@ov58XmZ5dItDgsL9@G@sDZS;@VeDo@~M{^|do61}hu~ zG&JfcbAB(gs_h;n*|r$rZ;_7+$Ni*Lg+((XW_2MT#J+0;R7Cnn@7Y%(ohr=L+`{ zrlF;f_H#0RSrzImYuCfR&!<6L;z}}u)mCkexQ9%8u=9Nu9XB_V9vSh`dlt-0mWNo! zD|_ba8M0DS?1E9FP}&p6&O54|!&yG-bCN%+lT0Qvnlqc>-OkRNTKR*%50uNSVST#B zrL~irmPa|wd2C@_eL+8RZObuhy-nb0BL6kEuXMRak$?D2z@WWV*f;r4%rcF@rJB)b zQY@ZPT~&D38&VpT=I>cT7(I86@rGW(k%4!X%sbTRrK&4WT5#opm5n&YEF>-u#>58qE P_z1W;okcaA#%BHtUqPk< literal 0 HcmV?d00001 diff --git a/files/opencs/raster/potion.png b/files/opencs/raster/potion.png new file mode 100644 index 0000000000000000000000000000000000000000..e644017641207da2d8858c2c8b00d0233239f55e GIT binary patch literal 1876 zcmV-a2dnsrP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000KVNklauk_J%ZmSs5?*aciz(B+6AA}W`lBF4(02~iHADi99QfI;Mnpj3(|5d;OKfCezA zfGC0k!s1b@rqy&leU}an1d+o@|9EEinR(ym`+2^<<9XhBz`VH(x#9d2N2B>Y);jO> zS!ur$KbJMs@61VD{i2V>n`F4pW4~e^j=FF4{$Bu0C3a?dhN6d7cFrn0kuG5?%n4DL zAlB8yOsY`n7>FJkTgc3212ZcJ9F*SqKAS%0>#CbXt#YI#Bb@5}p?FG-Nhze zhrtIh{150KfsQ-SDzqT=XcB;`1vk_n84W+Nv*Z@O@h8wWGQX={YbuZ_0W4&St7`G$ z`XSo7K_!Sjd;;Br!tRCn>2@el z+7UaifAq3YOac%}tu!{Tj;0@;(%;n2z2P6JTAo0;JdWz4SEdB`CbNYk@kaK1?<7_1=v~f2=~}>bS<4qf9}F004L8tRqoNtG;Ycpjk&6zm48K4(zQC9GPCWJ zZpx*iy#GZG6j!P^9Q;=&V{Yqp|CInD zOFOf#yc1}U#c?;c8I|fe&yQc@r;1JHa&Yll(zSdzsI#6El1MJP zrqUjoLuX7r?Gf2r5F9AA*(HDk6aUF7Lf@65G+o1@rPdQp%Lxuh4f6)}9bGL{Or zX!bAm$5Z=L7MaKj$A@78fUS#n%_(s>gF!{~x7?$@xN}r|Af$x8z#@A5^6BzBO6SIW zIyU6e>YvS}wTGxvrcmXy?}d1&&2ElaenElR4vvVz$u`Ov;;q?jPW45boOel{Ryxw5W3MS}nDc1V#Xc$VSt^##zK2`WXI40Uc@8;uF2`#rVvu!ln=VH5h=W6l4 zd=kKl-{@jsq7;s@iD$y3MkJQHlpZh*rNtv{RJ^SI-!umn&N}Af#karbhU_gPw8Zl1 zJE7387p$@Odz!5mK)YWaC(G_p8CO56gc~m&_tAP3zt+Y`*YW9$&H}YXhL#S6U)qFG zAP%Epeco${d;i`Ht3TSIu~a&t{>MTw<$b_dB)t{A)L*FK;2D?N&v&jCw|-lUrjCVh zZ<@t@K>e`VE(1f$p$L6nl7)k&Toyap;a=8c)O9{yeD}gNc>Yc_Dz2ezGBl?f(F+KP zbK_dEFX8XY1(0>*inmYbaO1^eK3pS|n+*A{gip0U*`q0TYM+*bqbyCLONrBv4s{J z+xRUpTUIMJb{erU^?YKdvmEIXXUs+JPxK8OMl?nCwHk)jelrmsd*;6>wBw{6A3SOR O0000WhV^AGn&==Nvijd%jsxGa8f0J_;jomDf%A^dQJ z&d?E(7b3I_rt(nI`NGmZaOvnWSh_0@#m6er7H!v{p_4Tc< zukY*Y16|_;g1xGS8$sZ^>=CW8jNyu7$vZbwH4g+jsO@!sCvDwWE_#Dv4)@cI1J)z$g=c{ew= z#>U2`rl#fPgty-U-tC$6c!fJ>2w~C zx45|Y`0-=tUrS5t;lqbSB5`0~prxf{aBvXXtE#GkibX|5wY9ZNOH1wT?Ik58t*xz= zmX>X8Z9r~rZtm~zhrQ(GB~jmmmw{n11YO6&`4}dn;<-{8h9%Qtz_3XH^{7r9 zCX0i@YDtaT1{p-*o9gRXxuDF3uE02ne z>wgWq!X+FC4n)NS>ku&XGD2dq;FQ%Ty^bU2u&x4OBs9=p=>5A`utv@-II9 zs^HRv9Ytgjm6esH%tI0rp2tZ&f8)}!R(l4cZMW+#B4M#k^#`fsgDwTJQhDS2 zb-$z9bi&trs{71RBn9o+(&Z%sKmGjh6N$qy@K?r;`~LicF+sNJMAFh?DN6J0RK`@r4ck3# zL}zNNgZ(#39%Znr{a$rJLc;XaJG~Ug;r-Q@F0zzM-Q9vHO4aanLa3tZkr&)c&+hI! z4Lr)s%&;S_Aj)$$&53qUbRxF+*?HyE#ZUMn4Nk;Ao$8AN1os3nJjyldIsGUKQ~2at z{F5m`RCIko98SF7p+Z4F|IFMt<=l;w)Oo){rM*M#z4;{knM%^B+*CPfZEcsMd}dcf z1t+OXcuOG>To1cqC}fJ0#c9HprZ;s%JYLqbo~w67ldW74p~l?(NDID9^`(35QNu99 z1)l4nn_8AlYi86s+{o>L@6F4n26om@+%id+rI&9c6DN)zNK*}@jpW!~9F8d7aDNwD zoqIob^{?QSbzJF&zxQhIq(e&Rl}Xiig5OG8UwCWlc%L*4&_*pjEorRR7vOh_c1pP) zN)zLyNj~DtBmm^e^zdRZy%=5|LJy`7lkLOuc4d0{FquahYD)eSkd~e(Nk0Am0gQPX w8v-oV6$I(Y(wz9rB$Shr<1RUonkA0UNODilJa+XJ#|lU&lp7IvGeD&H8)U$05dZ)H literal 0 HcmV?d00001 diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png new file mode 100644 index 0000000000000000000000000000000000000000..a8165827790baac034005d1b4729b02ad45e5f70 GIT binary patch literal 1474 zcmZ`%cTm$;9RFbrib}OARwz`joJC8~jDj>q4Iv98h+!{f2W13e0umr3fsh19f+T22 z$bk?MWQ9l)2pE>2oGb^`sy%Df7VF8<_D*s1(cbm!AN}6veb@Vb?|sJ;2l$h0*Ep>U7^#B(;v@M+%+D*-d9-X=0IC#}EJUWoYJ_*W*JQ`Zl zpwhO~NaSJ;kDW?S4hZxQ2tJ(4J=JDxl2=LT%v4`r($1Ybsln8$8il^QwawU=LQlqc zWAeG|JZ?^XW38d9!!p=ovgngi60lgTgM$N+Ow3@UilxPMO*MEtrqk4+P@ZmV)~aii z3A8w4uTE!bj!ih`;^Gn=6E2kSHT7pzwF+)=UT8#M#L=*@s9;drDGn)IibzK+RO#n^p#wIYUHbY~p z;X==#VPtIJQcr7VZ=0#F!#rr{8!-=$4UFF!othr&9WwO|cTY`^Pu{++Ij^j)KclKs zsO!#Xv}aZ46w*p@NqLc=l*=v7&E;iD6=HLr(K2M#XqB9zoB}~kp_n6*6_!>A#j?Vp zk^*gW?X`)an|CH|-I*L3wHSJJJYgPRln>@vCKpO8OXO7&ae0wY!t3h4q&inAlJX@A zQAJf5=m?N(LD~m|oJsW$ged-$L%u#fBq9Otjq}1DJg{s1UKA3EL?GaBRL$Q@sT@~q+xk?@cR=0paDO$Ip}{90SEA=@RZwb|}!5J2<6dj)x3kB`~P z;GPy&RS7C3nnHQ0T6k7=3>zTw3d0BaMd7Hv5yTLG&f?|`N_5(rGJ6zlLbabZ8wIl_ z>`1f=c4ygA++O6oblHPlgQ=!c^}4o{Ceo$DXkRJ!eQZ+>1VmRobMjk`JwX3g{T{wCRd>&nOF zKiJwtud|MQbXV*ARejx^mS_`aXvFYET-;+OV)GUHz23y<#uxjtX7635%~{^rh-cPR zcsO}>{WkT;nIv;Mn7MfS8EQ0naTjf}`aXjLBM%5lbN57BDoPr*yX|*Ix$bk>yQi;K z*Vv`)Y;i2OIn~5fA^79la54P90IMH;i~s-t literal 0 HcmV?d00001 diff --git a/files/opencs/raster/static.png b/files/opencs/raster/static.png new file mode 100644 index 0000000000000000000000000000000000000000..b53be12d9a8abad9272fdd7c6a75b1d3a6a494ba GIT binary patch literal 1518 zcmZ{kdpHw%7{`CZTxJ-Cxok(sA*?NQX1O$0o0FJZw8|yq&RlA3g(EHywCH#pXa@NpYMM!kLF9!f|WyX>)eRte=7=CC15NLd8sXdC>{K1z&!_ZHNLb7(&-i^$pDsLJnXU9&72fI{f-7|m zF|gqUd$2u!OSOjh@6iC^h~i{P%*wgaiH@`4-IlW$(-}guq2X=ms%UtDxHc6RUGQ5| zQ>zhiyz0XC}*TygO>%+5Vz7uDl-HQ;)|U@va&5yH@D~XW#<`! zxrI|=%kAnb=H?bkj$U-bym(m7kxFM(ZI7d;E13(2NPkEy1{u+86aA1ThWx&ANizhH zKo`He$h7_2yn%^F_TqCh4xh2V#;wptNIlzEeDFgs?Yd>dXkZ&%gzer{=rwAv>;$*b zX`!pT>D12EEyG-OZamvM92e)I$D?Cf4pAUz)yG>Xo9H290UDwJ?;Nw__%n68?LEg@ zn`h@r*cTwtNv2~WmwqAso-c3e;epsl!$MSb#k0ie*=Y;qeHLkDWwf=g&=isQT(DD3 zXqc)RBse4_M#uj_(sLQ%s}YtqGoWw0-r&1F^s4qm=fc>-PZf>?nap1e2M(huDoCgT zf^1c!rk|G75Y>lcFFVbfntq@d<1I|cr~y{Hbbzkiz1{CmTU6j+>k)ole0Tp$#JluH zf73FkZUN5TZrr*up9b5$c?+_6TKc#W$;MF5Q6HwM;BSTt61JW!(KSAd!8>w|2V0@K zwJn{K)@Td$5%Sau(B&GZC&6j3$K(6RlNvohbDihp9JlJs%F?x$?My$bR=-l-Zu@E3 zi)%q0IpNlAj;D$m&l)rd1oy88Ew*`g^gCd?tIl5<9JzX zW%9t+wQudFPx#aV%X9iq>UJbgL>9=hST6jV^nX@aZ$dVFDtqLXL=lRDH)z1T++~Zl zDV7bT7zj=7x;-{lxH7x5SZRK5COy9~0gixo_0I`!c3|5Dg2m(~(OXGfTQ-JSvB=7_ zqT;CT8*!;w`?SB*evbZ$$MDcog-EF7D9>H~r4-RjcK+-wsh!J1&|A}%l3(;IRJ;yR zdq%x-ry!Jn6l1TlN*7eS=tiK9Rp_?T$LX`*h9bGM6BmYiO9!|Y$KDZKH0q`nJ|7Gg z-W9HE!?=@GFujSr@Qei5TceF%CyOylHr1yDWn%qDkJ{HH=+%T^tHFykf&h(*0qOo$oL@Y0gLN=l)Plry|+wLh+UFZ8q_#K$TFFVZf*vCKO!jdRXx>{REYi(=3D{98` z@zcj()PBW#Tc5ctG&4FfGlm$I9-{!*gu^>J;2a$s@j-YT5x1G>>|%%8M8x5iAN=nA zA3<_zbo>F<{|gGsk;fDQ;~x%zsRuHdk?Apj$z)>VQxY?xA{jB*)b!X&iK~g?2zYPv KB{z9S9QzkRt&Y3^ literal 0 HcmV?d00001 diff --git a/files/opencs/raster/weapon.png b/files/opencs/raster/weapon.png new file mode 100644 index 0000000000000000000000000000000000000000..b68878a54abbadce500135ea0dd77e7e53168118 GIT binary patch literal 1064 zcmV+@1lRkCP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000A*NklC~g8kO*MPy}%<;wSyJmZstM`E*dS zB;<&=YZ3vchrGk4fJgJ68{u|#p}o-vm0Vyaa6T{jpGm`m#mI*?I~hDq;%Z9r5miti zn*vPDcMbUY^&#dyHRC~@7P9Qrwfi+E(0MZhHO54wat<$VgtM9exh!8P`%`mKgD)TM zVcOn+h8s#Kb5bKZXFUO#RBG?)>Ow_%`FfREg{il<;doPvTbHHCI>}uNch0H+0>4vV zkJ;H-EG#U*WGY#=l*lnLbQR+-t6{ZdB3s0>M_PFM?tvhDdU_fwD=V0pnZd}&2xyaO zou+bO>#4-6CuOKUCqkBx8=4MQ5;#Lq{lqze`~7~*&COwKYz)K0!|3blLt&wDy+|v; zKu0m2HyZdo3*t*w&1&3 zLRv#?hB4ku>fFzO4YILZONU zS11(z{lKFNAn;O}c5UaJ4R}NW1kSA3-|>KN5kTO~@sfS+cDoU&=BL$aA2St}z1BSH zCJe&KhlF%`Jm8@OE>%?>(`mJyAl&QqZt3=XmC7Z~$O!$*v6cXVlbT0^x3#rFE|dK} z2zVfY0-eq=I5-%HJ=}RqOADAW^BxpDAb_H%ccY`D@OV6%Vvh$rAb^?o?-LUfAcvHJ ztXBeOR;%YAoriwOsKP?$(9jTUHXFLTyV2Ct6sWmIqdCS_qiuIj0#jor(+5t2!SJ0K i#dmqRxsG_jiLn1=-XV(QI6oTz0000D> literal 0 HcmV?d00001 diff --git a/files/opencs/scalable/Palette.svg b/files/opencs/scalable/Palette.svg new file mode 100644 index 0000000000..f42475330d --- /dev/null +++ b/files/opencs/scalable/Palette.svg @@ -0,0 +1,569 @@ + + + + + + + image/svg+xml + + + + + + Tango Palette + + + Tuomas Kuosmanen + + + + + Garrett Le Sage +Kenneth Wimer +Jakub Steiner + + +http://www.tango-project.org/files/Tango-Palette.svg + + + unify + global + theme + color + palette + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/opencs/scalable/referenceable-record/.directory b/files/opencs/scalable/referenceable-record/.directory new file mode 100644 index 0000000000..e2d80ed58c --- /dev/null +++ b/files/opencs/scalable/referenceable-record/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/referenceable-record/activator.svg b/files/opencs/scalable/referenceable-record/activator.svg new file mode 100644 index 0000000000..0c6db59a7d --- /dev/null +++ b/files/opencs/scalable/referenceable-record/activator.svg @@ -0,0 +1,1088 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/apparatus.svg b/files/opencs/scalable/referenceable-record/apparatus.svg new file mode 100644 index 0000000000..37cef0e890 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/apparatus.svg @@ -0,0 +1,1058 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/book.svg b/files/opencs/scalable/referenceable-record/book.svg new file mode 100644 index 0000000000..8c041a9e7a --- /dev/null +++ b/files/opencs/scalable/referenceable-record/book.svg @@ -0,0 +1,692 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/container.svg b/files/opencs/scalable/referenceable-record/container.svg new file mode 100644 index 0000000000..8c9465b668 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/container.svg @@ -0,0 +1,1899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/ingredient.svg b/files/opencs/scalable/referenceable-record/ingredient.svg new file mode 100644 index 0000000000..a77a9c8ee7 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/ingredient.svg @@ -0,0 +1,1112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/light.svg b/files/opencs/scalable/referenceable-record/light.svg new file mode 100644 index 0000000000..f8f5066365 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/light.svg @@ -0,0 +1,1513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/miscellaneous.svg b/files/opencs/scalable/referenceable-record/miscellaneous.svg new file mode 100644 index 0000000000..96522048cb --- /dev/null +++ b/files/opencs/scalable/referenceable-record/miscellaneous.svg @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/potion.svg b/files/opencs/scalable/referenceable-record/potion.svg new file mode 100644 index 0000000000..552c14f19f --- /dev/null +++ b/files/opencs/scalable/referenceable-record/potion.svg @@ -0,0 +1,1161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/random-item.svg b/files/opencs/scalable/referenceable-record/random-item.svg new file mode 100644 index 0000000000..d051ce049f --- /dev/null +++ b/files/opencs/scalable/referenceable-record/random-item.svg @@ -0,0 +1,156 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/repair.svg b/files/opencs/scalable/referenceable-record/repair.svg new file mode 100644 index 0000000000..b1a23956e3 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/repair.svg @@ -0,0 +1,1280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/static.svg b/files/opencs/scalable/referenceable-record/static.svg new file mode 100644 index 0000000000..a6f29370f0 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/static.svg @@ -0,0 +1,1141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/referenceable-record/weapon.svg b/files/opencs/scalable/referenceable-record/weapon.svg new file mode 100644 index 0000000000..2e832fff76 --- /dev/null +++ b/files/opencs/scalable/referenceable-record/weapon.svg @@ -0,0 +1,1206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/.directory b/files/opencs/scalable/status/.directory new file mode 100644 index 0000000000..e2d80ed58c --- /dev/null +++ b/files/opencs/scalable/status/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,3,21,10,19,49 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/status/added.svg b/files/opencs/scalable/status/added.svg new file mode 100644 index 0000000000..e0af57002a --- /dev/null +++ b/files/opencs/scalable/status/added.svg @@ -0,0 +1,969 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/modified.svg b/files/opencs/scalable/status/modified.svg new file mode 100644 index 0000000000..e278ce596b --- /dev/null +++ b/files/opencs/scalable/status/modified.svg @@ -0,0 +1,1192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/status/removed.svg b/files/opencs/scalable/status/removed.svg new file mode 100644 index 0000000000..17719cfc87 --- /dev/null +++ b/files/opencs/scalable/status/removed.svg @@ -0,0 +1,969 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + From 13be61812a101d2278234044cf72a4bc5fd27440 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 10:16:02 +0200 Subject: [PATCH 0177/1537] Made the "Unknown class key" exception slightly more helpful --- apps/openmw/mwworld/class.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641a..1eb2f35bd0 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -184,10 +184,13 @@ namespace MWWorld const Class& Class::get (const std::string& key) { + if (key.empty()) + throw std::logic_error ("Class::get(): attempting to get an empty key"); + std::map >::const_iterator iter = sClasses.find (key); if (iter==sClasses.end()) - throw std::logic_error ("unknown class key: " + key); + throw std::logic_error ("Class::get(): unknown class key: " + key); return *iter->second; } From 7b02ec411bcb04fb667eda5c509a9b6b33bbe806 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 01:29:24 -0700 Subject: [PATCH 0178/1537] Apply the rotation when updating the character controller --- apps/openmw/mwclass/npc.cpp | 7 ++++++- apps/openmw/mwclass/npc.hpp | 3 +++ apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 61d081b4b1..e3733fe7c0 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -416,7 +416,12 @@ namespace MWClass { return Ogre::Vector3(getMovementSettings(ptr).mPosition); } - + + Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const + { + return Ogre::Vector3(getMovementSettings(ptr).mRotation); + } + bool Npc::isEssential (const MWWorld::Ptr& ptr) const { MWWorld::LiveCellRef *ref = diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 0f61fc8c91..1a10bce6c1 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -96,6 +96,9 @@ namespace MWClass ///< Return desired movement vector (determined based on movement settings, /// stance and stats). + virtual Ogre::Vector3 getRotationVector (const MWWorld::Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + 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/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 3bba065ff4..56de21d274 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -183,6 +183,7 @@ void CharacterController::update(float duration, Movement &movement) bool isrunning = cls.getStance(mPtr, MWWorld::Class::Run); bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); const Ogre::Vector3 &vec = cls.getMovementVector(mPtr); + const Ogre::Vector3 &rot = cls.getRotationVector(mPtr); speed = cls.getSpeed(mPtr); /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except @@ -232,6 +233,10 @@ void CharacterController::update(float duration, Movement &movement) } else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + + movement.mRotation[0] += rot.x * duration; + movement.mRotation[1] += rot.y * duration; + movement.mRotation[2] += rot.z * duration; } if(mAnimation && !mSkipAnim) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641a..571815d9e6 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -142,6 +142,11 @@ namespace MWWorld return Ogre::Vector3 (0, 0, 0); } + Ogre::Vector3 Class::getRotationVector (const Ptr& ptr) const + { + return Ogre::Vector3 (0, 0, 0); + } + std::pair, bool> Class::getEquipmentSlots (const Ptr& ptr) const { return std::make_pair (std::vector(), false); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 012a03bf62..36d7e97db0 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -150,6 +150,9 @@ namespace MWWorld ///< Return desired movement vector (determined based on movement settings, /// stance and stats). + virtual Ogre::Vector3 getRotationVector (const Ptr& ptr) const; + ///< Return desired rotations, as euler angles. + virtual std::pair, bool> getEquipmentSlots (const Ptr& ptr) const; ///< \return first: Return IDs of the slot this object can be equipped in; second: can object /// stay stacked when equipped? From 38d19d33d8029ecddfcc1b66f8d5a978e9b8d69e Mon Sep 17 00:00:00 2001 From: lazydev Date: Sat, 30 Mar 2013 22:18:34 +0400 Subject: [PATCH 0179/1537] fix for #634 --- apps/openmw/mwdialogue/filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index cd9908d3df..f7e9529568 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -198,7 +198,7 @@ bool MWDialogue::Filter::testSelectStructNumeric (const SelectWrapper& select) c if (imData.mNumLongs) return select.selectCompare (locals.mLongs[i]); - i -= script->mData.mNumShorts; + i -= script->mData.mNumLongs; return select.selectCompare (locals.mFloats.at (i)); } From b6f2b39a2fa0139300009975818a29377b2aaf36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 01:56:38 -0700 Subject: [PATCH 0180/1537] Clear the movement and rotation vector when getting them --- apps/openmw/mwclass/npc.cpp | 14 ++++++++++++-- apps/openmw/mwinput/inputmanagerimp.cpp | 6 ------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index e3733fe7c0..cd6b0def11 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -414,12 +414,22 @@ namespace MWClass Ogre::Vector3 Npc::getMovementVector (const MWWorld::Ptr& ptr) const { - return Ogre::Vector3(getMovementSettings(ptr).mPosition); + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mPosition); + movement.mPosition[0] = 0.0f; + movement.mPosition[1] = 0.0f; + movement.mPosition[2] = 0.0f; + return vec; } Ogre::Vector3 Npc::getRotationVector (const MWWorld::Ptr& ptr) const { - return Ogre::Vector3(getMovementSettings(ptr).mRotation); + MWMechanics::Movement &movement = getMovementSettings(ptr); + Ogre::Vector3 vec(movement.mRotation); + movement.mRotation[0] = 0.0f; + movement.mRotation[1] = 0.0f; + movement.mRotation[2] = 0.0f; + return vec; } bool Npc::isEssential (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 013c722c02..1d55ff84dd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -288,8 +288,6 @@ namespace MWInput triedToMove = true; mPlayer.setLeftRight (1); } - else - mPlayer.setLeftRight (0); if (actionIsActive(A_MoveForward)) { @@ -303,8 +301,6 @@ namespace MWInput mPlayer.setAutoMove (false); mPlayer.setForwardBackward (-1); } - else - mPlayer.setForwardBackward (0); mPlayer.setSneak(actionIsActive(A_Sneak)); @@ -313,8 +309,6 @@ namespace MWInput mPlayer.setUpDown (1); triedToMove = true; } - else - mPlayer.setUpDown (0); if (mAlwaysRunActive) mPlayer.setRunState(!actionIsActive(A_Run)); From 18e8ff7198b0b7247c3ba0fae5101ca0f653e106 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 02:24:44 -0700 Subject: [PATCH 0181/1537] Actually rotate the object when updating physics --- apps/openmw/mwworld/worldimp.cpp | 20 ++++++++++++++------ apps/openmw/mwworld/worldimp.hpp | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 37fa73279e..ae0e02c8c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -806,13 +806,8 @@ namespace MWWorld mPhysics->scaleObject(ptr); } - void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) + void World::rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust) { - Ogre::Vector3 rot; - rot.x = Ogre::Degree(x).valueRadians(); - rot.y = Ogre::Degree(y).valueRadians(); - rot.z = Ogre::Degree(z).valueRadians(); - if (mRendering->rotateObject(ptr, rot, adjust)) { // rotate physically iff renderer confirm so @@ -827,6 +822,14 @@ namespace MWWorld } } + void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) + { + rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), + Ogre::Degree(y).valueRadians(), + Ogre::Degree(z).valueRadians()), + adjust); + } + void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) { copyObjectToCell(ptr,Cell,pos); @@ -876,12 +879,17 @@ namespace MWWorld player = iter; continue; } + + rotateObjectImp(iter->first, Ogre::Vector3(iter->second.mRotation), true); + Ogre::Vector3 vec = mPhysics->move(iter->first, Ogre::Vector3(iter->second.mPosition), duration, !isSwimming(iter->first) && !isFlying(iter->first)); moveObjectImp(iter->first, vec.x, vec.y, vec.z); } if(player != actors.end()) { + rotateObjectImp(player->first, Ogre::Vector3(player->second.mRotation), true); + Ogre::Vector3 vec = mPhysics->move(player->first, Ogre::Vector3(player->second.mPosition), duration, !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8554d904a4..8cff50bd16 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -90,6 +90,8 @@ namespace MWWorld int getDaysPerMonth (int month) const; + void rotateObjectImp (const Ptr& ptr, Ogre::Vector3 rot, bool adjust); + bool moveObjectImp (const Ptr& ptr, float x, float y, float z); ///< @return true if the active cell (cell player is in) changed From 13c098266cbe17e49917ff3b1306765b9f853452 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 02:57:22 -0700 Subject: [PATCH 0182/1537] Pass player rotation through the movement settings --- apps/openmw/mwinput/inputmanagerimp.cpp | 8 ++++---- apps/openmw/mwworld/player.cpp | 16 ++++++++++++++++ apps/openmw/mwworld/player.hpp | 4 ++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 1d55ff84dd..c23efe5792 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -538,11 +538,11 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2 * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.state.X.rel * mCameraSensitivity * 0.2f; + float y = arg.state.Y.rel * mCameraSensitivity * 0.2f * (mInvertY ? -1 : 1) * mUIYMultiplier; - MWBase::World *world = MWBase::Environment::get().getWorld(); - world->rotateObject(world->getPlayer().getPlayer(), -y, 0.f, x, true); + mPlayer.setYaw(x); + mPlayer.setPitch(-y); if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index b01b929c46..ea8a02dee9 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -84,6 +84,22 @@ namespace MWWorld MWWorld::Class::get (ptr).setStance (ptr, MWWorld::Class::Sneak, sneak); } + void Player::setYaw(float yaw) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[2] = yaw; + } + void Player::setPitch(float pitch) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[0] = pitch; + } + void Player::setRoll(float roll) + { + MWWorld::Ptr ptr = getPlayer(); + MWWorld::Class::get(ptr).getMovementSettings(ptr).mRotation[1] = roll; + } + MWMechanics::DrawState_ Player::getDrawState() { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index d82d3fc329..c985510917 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -67,6 +67,10 @@ namespace MWWorld void setRunState(bool run); void setSneak(bool sneak); + + void setYaw(float yaw); + void setPitch(float pitch); + void setRoll(float roll); }; } #endif From 4836ba16f763ceca71cbc7557ebea44561d85184 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 03:50:20 -0700 Subject: [PATCH 0183/1537] Implement turning states --- apps/openmw/mwmechanics/character.cpp | 10 ++++++++++ apps/openmw/mwmechanics/character.hpp | 3 +++ 2 files changed, 13 insertions(+) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 56de21d274..7aff2e1d0c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -75,6 +75,9 @@ static const struct { { CharState_SneakLeft, "sneakleft" }, { CharState_SneakRight, "sneakright" }, + { CharState_TurnLeft, "turnleft" }, + { CharState_TurnRight, "turnright" }, + { CharState_Jump, "jump" }, { CharState_Death1, "death1" }, @@ -231,6 +234,13 @@ void CharacterController::update(float duration, Movement &movement) // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); } + else if(rot.z != 0.0f && !inwater && !sneak) + { + if(rot.z > 0.0f) + setState(CharState_TurnRight, true); + else if(rot.z < 0.0f) + setState(CharState_TurnLeft, true); + } else if(mAnimQueue.size() == 0) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 61efd0be0e..5b5a65f797 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -54,6 +54,9 @@ enum CharacterState { CharState_SneakLeft, CharState_SneakRight, + CharState_TurnLeft, + CharState_TurnRight, + CharState_Jump, /* Death states must be last! */ From b0199c703ce0f37fbb2ea0b4a65d9cd77e7a8c38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 13:13:46 +0200 Subject: [PATCH 0184/1537] Companion UI --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/dialoguemanager.hpp | 2 ++ apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 28 ++++++++++++------- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 2 ++ apps/openmw/mwgui/container.cpp | 3 ++ apps/openmw/mwgui/container.hpp | 4 +++ apps/openmw/mwgui/dialogue.cpp | 19 +++++++++++-- apps/openmw/mwgui/hud.cpp | 3 +- apps/openmw/mwgui/inventorywindow.cpp | 5 +--- apps/openmw/mwgui/inventorywindow.hpp | 4 +-- apps/openmw/mwgui/mode.hpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 14 ++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 ++ apps/openmw/mwmechanics/npcstats.cpp | 22 +++++++++++++-- apps/openmw/mwmechanics/npcstats.hpp | 5 ++++ apps/openmw/mwscript/locals.cpp | 24 ++++++++++++++++ apps/openmw/mwscript/locals.hpp | 1 + apps/openmw/mwscript/scriptmanagerimp.cpp | 2 +- files/mygui/CMakeLists.txt | 1 + files/mygui/openmw_container_window.layout | 2 +- files/mygui/openmw_inventory_window.layout | 3 +- files/mygui/openmw_text.skin.xml | 5 ++++ 23 files changed, 130 insertions(+), 27 deletions(-) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 41f56f9931..da8d474396 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair soulgemdialog + merchantrepair repair soulgemdialog companionwindow ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index db86385d4e..de39b212ad 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -25,6 +25,8 @@ namespace MWBase virtual ~DialogueManager() {} + virtual bool isInChoice() const = 0; + virtual void startDialogue (const MWWorld::Ptr& actor) = 0; virtual void addTopic (const std::string& topic) = 0; diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 58897dc740..4d66a77423 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -201,6 +201,7 @@ namespace MWBase ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons = std::vector()) = 0; + virtual void enterPressed () = 0; virtual int readPressedButton() = 0; ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) @@ -235,6 +236,7 @@ namespace MWBase virtual bool getPlayerSleeping() = 0; virtual void wakeUpPlayer() = 0; + virtual void showCompanionWindow(MWWorld::Ptr actor) = 0; virtual void startSpellMaking(MWWorld::Ptr actor) = 0; virtual void startEnchanting(MWWorld::Ptr actor) = 0; virtual void startSelfEnchanting(MWWorld::Ptr soulgem) = 0; diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index b75c514a29..9380ab76cd 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -117,6 +117,8 @@ namespace MWDialogue void DialogueManager::startDialogue (const MWWorld::Ptr& actor) { + mLastTopic = ""; + mChoice = -1; mIsInChoice = false; @@ -127,6 +129,9 @@ namespace MWDialogue mActorKnownTopics.clear(); + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + 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(); @@ -145,8 +150,6 @@ namespace MWDialogue { //initialise the GUI 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)); creatureStats.talkedToPlayer(); @@ -160,7 +163,7 @@ namespace MWDialogue MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); win->addText (Interpreter::fixDefinesDialog(info->mResponse, interpreterContext)); executeScript (info->mResultScript); - mLastTopic = it->mId; + mLastTopic = Misc::StringUtils::lowerCase(it->mId); mLastDialogue = *info; break; } @@ -398,6 +401,11 @@ namespace MWDialogue updateTopics(); } + bool DialogueManager::isInChoice() const + { + return mIsInChoice; + } + void DialogueManager::goodbyeSelected() { // Do not close the dialogue window if the player has to answer a question @@ -424,15 +432,13 @@ namespace MWDialogue if (mDialogueMap.find(mLastTopic) != mDialogueMap.end()) { - if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic) - { - Filter filter (mActor, mChoice, mTalkedTo); + Filter filter (mActor, mChoice, mTalkedTo); + if (mDialogueMap[mLastTopic].mType == ESM::Dialogue::Topic + || mDialogueMap[mLastTopic].mType == ESM::Dialogue::Greeting) + { if (const ESM::DialInfo *info = filter.search (mDialogueMap[mLastTopic], true)) { - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; std::string text = info->mResponse; parseText (text); @@ -440,10 +446,12 @@ namespace MWDialogue MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); executeScript (info->mResultScript); - mLastTopic = mLastTopic; mLastDialogue = *info; } } + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; } updateTopics(); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 337cf62478..a7bec31a6a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -54,6 +54,8 @@ namespace MWDialogue DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage); + virtual bool isInChoice() const; + virtual void startDialogue (const MWWorld::Ptr& actor); virtual void addTopic (const std::string& topic); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 98d818638a..8377669535 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -340,6 +340,9 @@ void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) drawItems(); mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + notifyItemDragged(object, mDragAndDrop->mDraggedCount); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); std::string sound = MWWorld::Class::get(object).getDownSoundId(object); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 49e60aa251..03bd519f7d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -82,6 +82,10 @@ namespace MWGui void setFilter(int filter); ///< set category filter void drawItems(); + /// fired when an item was moved by drag&drop. \n + /// if it was removed from this container, count will be negative. + virtual void notifyItemDragged(MWWorld::Ptr item, int count) {} + protected: bool mDisplayEquippedItems; bool mHighlightEquippedItems; diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 6875b20216..b3aa27617c 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -228,7 +228,8 @@ void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) void DialogueWindow::onSelectTopic(const std::string& topic, int id) { - if (!mEnabled) return; + if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + return; int separatorPos = 0; for (unsigned int i=0; igetItemCount(); ++i) @@ -248,6 +249,11 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) { mPersuasionDialog.setVisible(true); } + else if (topic == gmst.find("sCompanionShare")->getString()) + { + mWindowManager.pushGuiMode(GM_Companion); + mWindowManager.showCompanionWindow(mPtr); + } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) @@ -306,7 +312,10 @@ void DialogueWindow::setKeywords(std::list keyWords) { mTopicsList->clear(); - bool anyService = mServices > 0; + bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); + + bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); @@ -335,9 +344,13 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Repair) mTopicsList->addItem(gmst.find("sRepair")->getString()); - if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) + if (isCompanion) + mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); + + if (anyService) mTopicsList->addSeparator(); + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { mTopicsList->addItem(*it); diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 0a31a428b8..84526a28dd 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -234,7 +234,8 @@ void HUD::onWorldClicked(MyGUI::Widget* _sender) mDragAndDrop->mDraggedWidget = 0; MWBase::Environment::get().getWindowManager()->setDragDrop(false); - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); } else { diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 578ec3da3e..1943ff773a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -43,7 +43,6 @@ namespace MWGui getWidget(mAvatar, "Avatar"); getWidget(mAvatarImage, "AvatarImage"); getWidget(mEncumbranceBar, "EncumbranceBar"); - getWidget(mEncumbranceText, "EncumbranceBarT"); getWidget(mFilterAll, "AllButton"); getWidget(mFilterWeapon, "WeaponButton"); getWidget(mFilterApparel, "ApparelButton"); @@ -240,9 +239,7 @@ namespace MWGui 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)) ); + mEncumbranceBar->setValue(encumbrance, capacity); } void InventoryWindow::onFrame() diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 7c59bab506..95657672d3 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -5,6 +5,7 @@ #include "container.hpp" #include "window_pinnable_base.hpp" +#include "widgets.hpp" namespace MWGui { @@ -36,8 +37,7 @@ namespace MWGui MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; MyGUI::TextBox* mArmorRating; - MyGUI::ProgressBar* mEncumbranceBar; - MyGUI::TextBox* mEncumbranceText; + Widgets::MWDynamicStat* mEncumbranceBar; MyGUI::Widget* mLeftPane; MyGUI::Widget* mRightPane; diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index e9b01395f0..879fcb483f 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -9,6 +9,7 @@ namespace MWGui GM_Settings, // Settings window GM_Inventory, // Inventory mode GM_Container, + GM_Companion, GM_MainMenu, // Main menu mode GM_Console, // Console mode diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eadd657871..cf14c1f514 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -58,6 +58,7 @@ #include "merchantrepair.hpp" #include "repair.hpp" #include "soulgemdialog.hpp" +#include "companionwindow.hpp" using namespace MWGui; @@ -96,6 +97,7 @@ WindowManager::WindowManager( , mMerchantRepair(NULL) , mRepair(NULL) , mSoulgemDialog(NULL) + , mCompanionWindow(NULL) , mPlayerName() , mPlayerRaceId() , mPlayerAttributes() @@ -189,6 +191,7 @@ WindowManager::WindowManager( mMerchantRepair = new MerchantRepair(*this); mRepair = new Repair(*this); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(*this, mDragAndDrop, mMessageBoxManager); mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -317,6 +320,7 @@ void WindowManager::updateVisible() mTrainingWindow->setVisible(false); mMerchantRepair->setVisible(false); mRepair->setVisible(false); + mCompanionWindow->setVisible(false); mHud->setVisible(mHudEnabled); @@ -417,6 +421,10 @@ void WindowManager::updateVisible() mContainerWindow->setVisible(true); mInventoryWindow->setVisible(true); break; + case GM_Companion: + mCompanionWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; case GM_Dialogue: mDialogueWindow->setVisible(true); break; @@ -676,6 +684,7 @@ void WindowManager::onFrame (float frameDuration) mSpellCreationDialog->checkReferenceAvailable(); mEnchantingDialog->checkReferenceAvailable(); mContainerWindow->checkReferenceAvailable(); + mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); } @@ -1167,6 +1176,11 @@ const Translation::Storage& WindowManager::getTranslationDataStorage() const return mTranslationDataStorage; } +void WindowManager::showCompanionWindow(MWWorld::Ptr actor) +{ + mCompanionWindow->open(actor); +} + void WindowManager::changePointer(const std::string &name) { mCursor->onCursorChange(name); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 5cf7bae02d..7a7adec27d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -77,6 +77,7 @@ namespace MWGui class MerchantRepair; class Repair; class SoulgemDialog; + class CompanionWindow; class WindowManager : public MWBase::WindowManager { @@ -229,6 +230,7 @@ namespace MWGui virtual bool getPlayerSleeping(); virtual void wakeUpPlayer(); + virtual void showCompanionWindow(MWWorld::Ptr actor); virtual void startSpellMaking(MWWorld::Ptr actor); virtual void startEnchanting(MWWorld::Ptr actor); virtual void startSelfEnchanting(MWWorld::Ptr soulgem); @@ -279,6 +281,7 @@ namespace MWGui MerchantRepair* mMerchantRepair; SoulgemDialog* mSoulgemDialog; Repair* mRepair; + CompanionWindow* mCompanionWindow; Translation::Storage& mTranslationDataStorage; Cursor* mCursor; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 51e23d16ea..b9aee6abf3 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -21,8 +21,16 @@ #include "../mwbase/soundmanager.hpp" MWMechanics::NpcStats::NpcStats() -: mMovementFlags (0), mDrawState (DrawState_Nothing), mBounty (0) -, mLevelProgress(0), mDisposition(0), mVampire (0), mReputation(0), mWerewolf (false), mWerewolfKills (0) +: mMovementFlags (0) +, mDrawState (DrawState_Nothing) +, mBounty (0) +, mLevelProgress(0) +, mDisposition(0) +, mVampire (0) +, mReputation(0) +, mWerewolf (false) +, mWerewolfKills (0) +, mProfit(0) { mSkillIncreases.resize (ESM::Attribute::Length); for (int i=0; igetLocals(script); + int index = locals.getIndex(var); + char type = locals.getType(var); + if(index != -1) + { + switch(type) + { + case 's': + return mShorts.at (index); + + case 'l': + return mLongs.at (index); + + case 'f': + return mFloats.at (index); + default: + return 0; + } + } + return 0; + } bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) { diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index e933c727f3..1d9b9c3e4f 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -17,6 +17,7 @@ namespace MWScript void configure (const ESM::Script& script); bool setVarByInt(const std::string& script, const std::string& var, int val); + int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0 }; } diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index fed5877c4b..933a6e0d3b 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -114,7 +114,7 @@ namespace MWScript } catch (const std::exception& e) { - std::cerr << "exeution of script " << name << " failed." << std::endl; + std::cerr << "execution of script " << name << " failed." << std::endl; if (mVerbose) std::cerr << "(" << e.what() << ")" << std::endl; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 7da28f0bfa..af695ac6c5 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_persuasion_dialog.layout openmw_merchantrepair.layout openmw_repair.layout + openmw_companion_window.layout smallbars.png DejaVuLGCSansMono.ttf markers.png diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 452196aaea..69961e9be6 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_inventory_window.layout b/files/mygui/openmw_inventory_window.layout index 41bd40f923..09842f1087 100644 --- a/files/mygui/openmw_inventory_window.layout +++ b/files/mygui/openmw_inventory_window.layout @@ -6,8 +6,7 @@ - - + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 71e86091c8..b2a15b503b 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -158,6 +158,11 @@ + + + + + From af6409b9f57880c5f8e796b62d2fd62183ddb589 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 13:50:57 +0200 Subject: [PATCH 0185/1537] Fix NPC physics scale problem --- libs/openengine/bullet/physic.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 8de931bbf8..7b831d32c5 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -89,18 +89,19 @@ namespace Physic } void PhysicActor::setScale(float scale){ - Ogre::Vector3 position = getPosition(); - Ogre::Quaternion rotation = getRotation(); //We only need to change the scaled box translation, box rotations remain the same. mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX(); mBoxScaledTranslation *= scale; if(mBody){ mEngine->dynamicsWorld->removeRigidBody(mBody); + mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); delete mBody; + delete mRaycastingBody; } //Create the newly scaled rigid body - mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation); - mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map + mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation()); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation(), 0, 0, true); + mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } Ogre::Vector3 PhysicActor::getHalfExtents() const From bc6e1fd9816f3acb914be559e7e79b4d84edb477 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 14:36:03 +0200 Subject: [PATCH 0186/1537] Add missing files --- apps/openmw/mwgui/companionwindow.cpp | 107 +++++++++++++++++++++ apps/openmw/mwgui/companionwindow.hpp | 39 ++++++++ files/mygui/openmw_companion_window.layout | 26 +++++ 3 files changed, 172 insertions(+) create mode 100644 apps/openmw/mwgui/companionwindow.cpp create mode 100644 apps/openmw/mwgui/companionwindow.hpp create mode 100644 files/mygui/openmw_companion_window.layout diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp new file mode 100644 index 0000000000..643cdf4c65 --- /dev/null +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -0,0 +1,107 @@ +#include "companionwindow.hpp" + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/dialoguemanager.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "messagebox.hpp" + +namespace MWGui +{ + +CompanionWindow::CompanionWindow(MWBase::WindowManager &parWindowManager, DragAndDrop *dragAndDrop, MessageBoxManager* manager) + : ContainerBase(dragAndDrop) + , WindowBase("openmw_companion_window.layout", parWindowManager) + , mMessageBoxManager(manager) +{ + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + getWidget(mCloseButton, "CloseButton"); + getWidget(mProfitLabel, "ProfitLabel"); + getWidget(mEncumbranceBar, "EncumbranceBar"); + + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CompanionWindow::onCloseButtonClicked); + + setCoord(200,0,600,300); +} + +void CompanionWindow::open(MWWorld::Ptr npc) +{ + openContainer(npc); + setTitle(MWWorld::Class::get(npc).getName(npc)); + drawItems(); + updateEncumbranceBar(); +} + +void CompanionWindow::notifyItemDragged(MWWorld::Ptr item, int count) +{ + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + MWMechanics::NpcStats& stats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); + stats.modifyProfit(MWWorld::Class::get(item).getValue(item) * count); + } + updateEncumbranceBar(); +} + +void CompanionWindow::updateEncumbranceBar() +{ + float capacity = MWWorld::Class::get(mPtr).getCapacity(mPtr); + float encumbrance = MWWorld::Class::get(mPtr).getEncumbrance(mPtr); + mEncumbranceBar->setValue(encumbrance, capacity); + + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + mProfitLabel->setCaption(""); + else + { + MWMechanics::NpcStats& stats = MWWorld::Class::get(mPtr).getNpcStats(mPtr); + mProfitLabel->setCaptionWithReplacing("#{sProfitValue} " + boost::lexical_cast(stats.getProfit())); + } +} + +void CompanionWindow::onWindowResize(MyGUI::Window* window) +{ + drawItems(); +} + +void CompanionWindow::onCloseButtonClicked(MyGUI::Widget* _sender) +{ + if (mPtr.getTypeName() == typeid(ESM::NPC).name() && MWWorld::Class::get(mPtr).getNpcStats(mPtr).getProfit() < 0) + { + std::vector buttons; + buttons.push_back("#{sCompanionWarningButtonOne}"); + buttons.push_back("#{sCompanionWarningButtonTwo}"); + mMessageBoxManager->createInteractiveMessageBox("#{sCompanionWarningMessage}", buttons); + mMessageBoxManager->eventButtonPressed += MyGUI::newDelegate(this, &CompanionWindow::onMessageBoxButtonClicked); + } + else + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); +} + +void CompanionWindow::onMessageBoxButtonClicked(int button) +{ + if (button == 0) + { + mPtr.getRefData().getLocals().setVarByInt(MWWorld::Class::get(mPtr).getScript(mPtr), + "minimumProfit", MWWorld::Class::get(mPtr).getNpcStats(mPtr).getProfit()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); + MWBase::Environment::get().getDialogueManager()->startDialogue (mPtr); + } +} + +void CompanionWindow::onReferenceUnavailable() +{ + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Companion); +} + + + +} diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp new file mode 100644 index 0000000000..1b64a34d50 --- /dev/null +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_MWGUI_COMPANIONWINDOW_H +#define OPENMW_MWGUI_COMPANIONWINDOW_H + +#include "container.hpp" +#include "widgets.hpp" + +namespace MWGui +{ + class MessageBoxManager; + + class CompanionWindow : public ContainerBase, public WindowBase + { + public: + CompanionWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop, MessageBoxManager* manager); + virtual ~CompanionWindow() {} + + void open(MWWorld::Ptr npc); + + virtual void notifyItemDragged(MWWorld::Ptr item, int count); + + protected: + MyGUI::Button* mCloseButton; + MyGUI::TextBox* mProfitLabel; + Widgets::MWDynamicStat* mEncumbranceBar; + MessageBoxManager* mMessageBoxManager; + + void onMessageBoxButtonClicked(int button); + + void updateEncumbranceBar(); + + void onWindowResize(MyGUI::Window* window); + void onCloseButtonClicked(MyGUI::Widget* _sender); + + virtual void onReferenceUnavailable(); + }; + +} + +#endif diff --git a/files/mygui/openmw_companion_window.layout b/files/mygui/openmw_companion_window.layout new file mode 100644 index 0000000000..6172dd5b10 --- /dev/null +++ b/files/mygui/openmw_companion_window.layout @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + From fd0aa1a4b82c4b94bc99657c1c64272e20b95c05 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 31 Mar 2013 14:46:46 +0200 Subject: [PATCH 0187/1537] Issue #685: Treat : as a whitespace --- components/compiler/scanner.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 7f43c36a55..420fd8f7f3 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -106,6 +106,12 @@ namespace Compiler mLoc.mLiteral.clear(); return true; } + else if (c==':') + { + // treat : as a whitespace :( + mLoc.mLiteral.clear(); + return true; + } else if (std::isdigit (c)) { bool cont = false; From 857f2b33dbdb14d5a0778929a0de7d12575ffa13 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 14:48:48 +0200 Subject: [PATCH 0188/1537] Fix companion layout align --- files/mygui/openmw_companion_window.layout | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/mygui/openmw_companion_window.layout b/files/mygui/openmw_companion_window.layout index 6172dd5b10..41a97a1ae5 100644 --- a/files/mygui/openmw_companion_window.layout +++ b/files/mygui/openmw_companion_window.layout @@ -11,7 +11,7 @@ - + From 8fd961bbac29bddb7bc838c7ed29e4268ed340c7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 31 Mar 2013 15:50:48 +0200 Subject: [PATCH 0189/1537] Fix ReferenceInterface not resetting the Ptr after it was deleted, causing onReferenceUnavailable to be called every frame. Fix inputmanager hiding the cursor when it shouldn't. --- apps/openmw/mwgui/referenceinterface.cpp | 3 +++ apps/openmw/mwinput/inputmanagerimp.cpp | 25 +++++------------------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index b1f7affb6f..66e036d929 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -26,7 +26,10 @@ namespace MWGui // check if player has changed cell, or count of the reference has become 0 if ((playerCell != mCurrentPlayerCell && mCurrentPlayerCell != NULL) || mPtr.getRefData().getCount() == 0) + { + mPtr = MWWorld::Ptr(); onReferenceUnavailable(); + } mCurrentPlayerCell = playerCell; } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 33ab9b1b40..e514638bb4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -372,26 +372,11 @@ namespace MWInput void InputManager::changeInputMode(bool guiMode) { MWBase::Environment::get().getWindowManager()->setMouseVisible(guiMode); - if(guiMode) - { - // Disable mouse look - mMouseLookEnabled = false; - - mWindows.showCrosshair (false); - - // Enable GUI events - mGuiCursorEnabled = true; - } - else - { - // Enable mouse look - mMouseLookEnabled = true; - - mWindows.showCrosshair (false); - - // Disable GUI events - mGuiCursorEnabled = false; - } + mGuiCursorEnabled = guiMode; + mMouseLookEnabled = !guiMode; + if (guiMode) + mWindows.showCrosshair(false); + // if not in gui mode, the camera decides whether to show crosshair or not. } void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed) From acae815cd23edd087e7e848cb92b7d51e178a571 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sun, 31 Mar 2013 18:00:46 +0200 Subject: [PATCH 0190/1537] Added workaround for OpenCS compilation problems due to bug in Qt MOC compiler. For details please see: https://forum.openmw.org/viewtopic.php?f=7&t=1451 https://bugreports.qt-project.org/browse/QTBUG-22829 Signed-off-by: Lukasz Gromanowski --- apps/opencs/editor.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/editor.hpp b/apps/opencs/editor.hpp index c242a17ea8..cbdbad36f8 100644 --- a/apps/opencs/editor.hpp +++ b/apps/opencs/editor.hpp @@ -2,9 +2,9 @@ #define CS_EDITOR_H #include - +#ifndef Q_MOC_RUN #include - +#endif #include "model/doc/documentmanager.hpp" #include "view/doc/viewmanager.hpp" From 63424ade56fd9c7da96446d666e4c4e774f1c4c0 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 31 Mar 2013 17:30:03 +0000 Subject: [PATCH 0191/1537] refactoring --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/aitravel.cpp | 177 ++------------------- apps/openmw/mwmechanics/aitravel.hpp | 8 +- apps/openmw/mwmechanics/pathfinding.cpp | 201 ++++++++++++++++++++++++ apps/openmw/mwmechanics/pathfinding.hpp | 26 +++ 5 files changed, 245 insertions(+), 169 deletions(-) create mode 100644 apps/openmw/mwmechanics/pathfinding.cpp create mode 100644 apps/openmw/mwmechanics/pathfinding.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 41599b35db..d29e0ff2e7 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -65,7 +65,7 @@ add_openmw_dir (mwclass add_openmw_dir (mwmechanics mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow - aiescort aiactivate repair + aiescort aiactivate repair pathfinding ) add_openmw_dir (mwbase diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 2c5260a625..df6a38bb03 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -14,7 +14,7 @@ #include "boost/tuple/tuple.hpp" MWMechanics::AiTravel::AiTravel(float x, float y, float z) -: mX(x),mY(y),mZ(z),isPathConstructed(false) + : mX(x),mY(y),mZ(z),mPathFinder() { } @@ -23,151 +23,17 @@ MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const return new AiTravel(*this); } -float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point point,float x,float y,float z) -{ - return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); -} - -float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) -{ - return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); -} - -int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) -{ - if(!grid) return -1; - if(grid->mPoints.empty()) return -1; - - float m = distance(grid->mPoints[0],x,y,z); - int i0 = 0; - - for(unsigned int i=1; imPoints.size();++i) - { - if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); - i0 = i; - } - } - return i0; -} - float sgn(float a) { if(a>0) return 1.; else return -1.; } -float getZAngle(float dX,float dY) -{ - float h = sqrt(dX*dX+dY*dY); - return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); -} - -typedef boost::adjacency_list,boost::property > PathGridGraph; -typedef boost::property_map::type WeightMap; -typedef PathGridGraph::vertex_descriptor PointID; -typedef PathGridGraph::edge_descriptor PointConnectionID; - -struct found_path {}; - -class goalVisited : public boost::default_astar_visitor -{ -public: - goalVisited(PointID goal) : mGoal(goal) {} - - void examine_vertex(PointID u, const PathGridGraph g) - { - if(u == mGoal) - throw found_path(); - } -private: - PointID mGoal; -}; - -class DistanceHeuristic : public boost::astar_heuristic -{ -public: - DistanceHeuristic(const PathGridGraph & l, PointID goal) - : mGraph(l), mGoal(goal) {} - - float operator()(PointID u) - { - const ESM::Pathgrid::Point & U = mGraph[u]; - const ESM::Pathgrid::Point & V = mGraph[mGoal]; - float dx = U.mX - V.mX; - float dy = U.mY - V.mY; - float dz = U.mZ - V.mZ; - return sqrt(dx * dx + dy * dy + dz * dz); - } -private: - const PathGridGraph & mGraph; - PointID mGoal; -}; - -std::list getPath(PointID start,PointID end,PathGridGraph graph){ - std::vector p(boost::num_vertices(graph)); - std::vector d(boost::num_vertices(graph)); - std::list shortest_path; - - try { - boost::astar_search - ( - graph, - start, - DistanceHeuristic(graph,end), - boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); - - } catch(found_path fg) { - for(PointID v = end;; v = p[v]) { - shortest_path.push_front(graph[v]); - if(p[v] == v) - break; - } - } - return shortest_path; -} - -PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) -{ - PathGridGraph graph; - - for(unsigned int i = 0;imPoints.size();++i) - { - PointID pID = boost::add_vertex(graph); - graph[pID].mX = pathgrid->mPoints[i].mX + xCell; - graph[pID].mY = pathgrid->mPoints[i].mY + yCell; - graph[pID].mZ = pathgrid->mPoints[i].mZ; - } - - for(unsigned int i = 0;imEdges.size();++i) - { - PointID u = pathgrid->mEdges[i].mV0; - PointID v = pathgrid->mEdges[i].mV1; - - PointConnectionID edge; - bool done; - boost::tie(edge,done) = boost::add_edge(u,v,graph); - WeightMap weightmap = boost::get(boost::edge_weight, graph); - weightmap[edge] = distance(graph[u],graph[v]); - - } - - return graph; -} - bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - + ESM::Position pos = actor.getRefData().getPosition(); bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; @@ -193,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!isPathConstructed ||cellChange) + if(!mPathFinder.mIsPathConstructed ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -205,43 +71,26 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; } - int start = getClosestPoint(pathgrid,pos.pos[0] - xCell,pos.pos[1] - yCell,pos.pos[2]); - int end = getClosestPoint(pathgrid,mX - xCell,mY - yCell,mZ); - - if(start != -1 && end != -1) - { - PathGridGraph graph = buildGraph(pathgrid,xCell,yCell); - mPath = getPath(start,end,graph); - } - ESM::Pathgrid::Point dest; dest.mX = mX; dest.mY = mY; dest.mZ = mZ; - mPath.push_back(dest); - isPathConstructed = true; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); } - if(mPath.empty()) + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } - ESM::Pathgrid::Point nextPoint = *mPath.begin(); - if(distanceZCorrected(nextPoint,pos.pos[0],pos.pos[1],pos.pos[2]) < 20) - { - mPath.pop_front(); - if(mPath.empty()) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - nextPoint = *mPath.begin(); - } - - float dX = nextPoint.mX - pos.pos[0]; - float dY = nextPoint.mY - pos.pos[1]; - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,getZAngle(dX,dY),false); + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; return false; diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index ef2359ba91..52b41850f1 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -2,8 +2,7 @@ #define GAME_MWMECHANICS_AITRAVEL_H #include "aipackage.hpp" -#include -#include +#include "pathfinding.hpp" namespace MWMechanics { @@ -26,8 +25,9 @@ namespace MWMechanics int cellX; int cellY; - bool isPathConstructed; - std::list mPath; + //bool isPathConstructed; + //std::list mPath; + PathFinder mPathFinder; }; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp new file mode 100644 index 0000000000..9b76082b48 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -0,0 +1,201 @@ +#include "pathfinding.hpp" +#include +#include +#include "boost/tuple/tuple.hpp" +#include "OgreMath.h" + +namespace MWMechanics +{ + + //helpers functions + float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point point,float x,float y,float z) + { + return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+(point.mZ - z)*(point.mZ - z)); + } + + float distance(ESM::Pathgrid::Point a,ESM::Pathgrid::Point b) + { + return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + int getClosestPoint(const ESM::Pathgrid* grid,float x,float y,float z) + { + if(!grid) return -1; + if(grid->mPoints.empty()) return -1; + + float m = distance(grid->mPoints[0],x,y,z); + int i0 = 0; + + for(unsigned int i=1; imPoints.size();++i) + { + if(distance(grid->mPoints[i],x,y,z)mPoints[i],x,y,z); + i0 = i; + } + } + return i0; + } + + typedef boost::adjacency_list,boost::property > PathGridGraph; + typedef boost::property_map::type WeightMap; + typedef PathGridGraph::vertex_descriptor PointID; + typedef PathGridGraph::edge_descriptor PointConnectionID; + + struct found_path {}; + + class goalVisited : public boost::default_astar_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + + class DistanceHeuristic : public boost::astar_heuristic + { + public: + DistanceHeuristic(const PathGridGraph & l, PointID goal) + : mGraph(l), mGoal(goal) {} + + float operator()(PointID u) + { + const ESM::Pathgrid::Point & U = mGraph[u]; + const ESM::Pathgrid::Point & V = mGraph[mGoal]; + float dx = U.mX - V.mX; + float dy = U.mY - V.mY; + float dz = U.mZ - V.mZ; + return sqrt(dx * dx + dy * dy + dz * dz); + } + private: + const PathGridGraph & mGraph; + PointID mGoal; + }; + + PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) + { + PathGridGraph graph; + + for(unsigned int i = 0;imPoints.size();++i) + { + PointID pID = boost::add_vertex(graph); + graph[pID].mX = pathgrid->mPoints[i].mX + xCell; + graph[pID].mY = pathgrid->mPoints[i].mY + yCell; + graph[pID].mZ = pathgrid->mPoints[i].mZ; + } + + for(unsigned int i = 0;imEdges.size();++i) + { + PointID u = pathgrid->mEdges[i].mV0; + PointID v = pathgrid->mEdges[i].mV1; + + PointConnectionID edge; + bool done; + boost::tie(edge,done) = boost::add_edge(u,v,graph); + WeightMap weightmap = boost::get(boost::edge_weight, graph); + weightmap[edge] = distance(graph[u],graph[v]); + + } + + return graph; + } + + std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::vector p(boost::num_vertices(graph)); + std::vector d(boost::num_vertices(graph)); + std::list shortest_path; + + try { + boost::astar_search + ( + graph, + start, + DistanceHeuristic(graph,end), + boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) + ); + + } catch(found_path fg) { + for(PointID v = end;; v = p[v]) { + shortest_path.push_front(graph[v]); + if(p[v] == v) + break; + } + } + return shortest_path; + } + + //end of helpers functions + + PathFinder::PathFinder() + { + mIsPathConstructed = false; + } + + std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell,float yCell) + { + int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); + int end = getClosestPoint(pathGrid,endPoint.mX - xCell,endPoint.mY - yCell,endPoint.mZ); + + if(start != -1 && end != -1) + { + PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); + mPath = getPath(start,end,graph); + } + + mPath.push_back(endPoint); + mIsPathConstructed = true; + + return mPath; + } + + float PathFinder::getZAngleToNext(float x,float y,float z) + { + if(mPath.empty()) + { + return 0;/// shouldn't happen! + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + float dX = nextPoint.mX - x; + float dY = nextPoint.mY - y; + float h = sqrt(dX*dX+dY*dY); + return Ogre::Radian(acos(dY/h)*sgn(asin(dX/h))).valueDegrees(); + } + + bool PathFinder::checkIfNextPointReached(float x,float y,float z) + { + if(mPath.empty()) + { + return true; + } + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + if(distanceZCorrected(nextPoint,x,y,z) < 20) + { + mPath.pop_front(); + if(mPath.empty()) + { + return true; + } + nextPoint = *mPath.begin(); + } + return false; + } +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp new file mode 100644 index 0000000000..200b191259 --- /dev/null +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -0,0 +1,26 @@ +#ifndef GAME_MWMECHANICS_PATHFINDING_H +#define GAME_MWMECHANICS_PATHFINDING_H + +#include +#include + +namespace MWMechanics +{ + class PathFinder + { + public: + PathFinder(); + + std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); + + bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. + float getZAngleToNext(float x,float y,float z); + + + std::list mPath; + bool mIsPathConstructed; + }; +} + +#endif \ No newline at end of file From d29a42dcbe37b968827b7648eab6ce8f345bbf66 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 31 Mar 2013 23:18:23 +0200 Subject: [PATCH 0192/1537] Fixed enchanting mechanics --- apps/openmw/mwclass/armor.cpp | 4 ++-- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/book.cpp | 4 ++-- apps/openmw/mwclass/book.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 4 ++-- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 4 ++-- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwgui/enchantingdialog.cpp | 12 +++++++++--- apps/openmw/mwmechanics/enchanting.cpp | 21 +++++++++++---------- apps/openmw/mwmechanics/enchanting.hpp | 4 +++- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- 13 files changed, 37 insertions(+), 28 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 281dd1f42c..b94c270d56 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -274,7 +274,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Armor::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -285,7 +285,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Armor *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 0c32015a35..65f49abb7d 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -65,7 +65,7 @@ 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 std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 644561e52b..85b006160b 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -147,7 +147,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Book::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -159,7 +159,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Book *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index c17d4255b1..29e3de0361 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -51,7 +51,7 @@ 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 std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; 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 8f29a2084d..d65376898e 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -221,7 +221,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Clothing::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -232,7 +232,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Clothing *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4457e79fb6..c3ef22f113 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -59,7 +59,7 @@ 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 std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 894b38acc9..ed2a095e37 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -367,7 +367,7 @@ namespace MWClass return ref->mBase->mEnchant; } - std::string Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Weapon::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { MWWorld::LiveCellRef *ref = ptr.get(); @@ -378,7 +378,7 @@ namespace MWClass newItem.mData.mEnchant=enchCharge; newItem.mEnchant=enchId; const ESM::Weapon *record = MWBase::Environment::get().getWorld()->createRecord (newItem); - return record->mId; + ref->mBase = record; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 533f32f592..4774bb50be 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -65,7 +65,7 @@ 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 std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 7d5d1411f9..0f3b8b7cb0 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -86,10 +86,16 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(actor); - mPtr = actor; + /*Now there's no need to use other enchanters, player is the enchanter here, + even if the enchanted object is created by NPC. Could be changed later, probably + with some price formulas */ + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + mEnchanting.setSelfEnchanting(false); + mEnchanting.setEnchanter(player); + + mPtr = player; startEditing (); } diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 3590ae0f3f..ba4e46de79 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -20,6 +20,7 @@ namespace MWMechanics { mObjectType = mOldItemPtr.getTypeName(); mOldItemId = mOldItemPtr.getCellRef().mRefID; + mOldItemCount = mOldItemPtr.getRefData().getCount(); } else { @@ -50,7 +51,8 @@ namespace MWMechanics int Enchanting::create() { - mSoulGemPtr.getRefData().setCount(mSoulGemPtr.getRefData().getCount()-1); + mEnchantment.mData.mCharge = getGemCharge(); + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { @@ -60,9 +62,6 @@ namespace MWMechanics MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } - mOldItemPtr.getRefData().setCount(mOldItemPtr.getRefData().getCount()-1); - - mEnchantment.mData.mCharge = getGemCharge(); if(mEnchantType==3) { mEnchantment.mData.mCharge=0; @@ -70,15 +69,17 @@ namespace MWMechanics mEnchantment.mData.mType = mEnchantType; mEnchantment.mData.mCost = getEnchantCost(); mEnchantment.mEffects = mEffectList; + const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); - std::string newobjId = MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + + mOldItemPtr.getRefData().setCount(1); + + MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); + ref.getPtr().getRefData().setCount (mOldItemCount-1); + MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), newobjId); - MWWorld::Ptr newobjPtr = ref.getPtr(); - MWWorld::Ptr result = mOldItemPtr; - result.mPtr = newobjPtr.mPtr; - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (result); return 1; } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index fffa2c5b20..1a7dde708c 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -13,7 +13,7 @@ namespace MWMechanics MWWorld::Ptr mOldItemPtr; MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; - const MWWorld::Ptr *mNewItemPtr; + int mEnchantType; bool mSelfEnchanting; @@ -24,6 +24,8 @@ namespace MWMechanics std::string mNewItemName; std::string mObjectType; std::string mOldItemId; + int mOldItemCount; + public: Enchanting(); void setEnchanter(MWWorld::Ptr enchanter); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 876328641a..9a83063c03 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -246,7 +246,7 @@ namespace MWWorld return ""; } - std::string Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const + void Class::applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const { throw std::runtime_error ("class can't be enchanted"); } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 012a03bf62..2f010eb3d7 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -234,7 +234,7 @@ namespace MWWorld virtual std::string getModel(const MWWorld::Ptr &ptr) const; - virtual std::string applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; From 10d04c928c894d512e999b52e8cea77e8c01eea7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 15:12:10 -0700 Subject: [PATCH 0193/1537] Use the object's class to check if it's an actor --- .../mwmechanics/mechanicsmanagerimp.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 32fa58980d..0af7a46655 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -178,10 +178,10 @@ namespace MWMechanics void MechanicsManager::add(const MWWorld::Ptr& ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.addActivator(ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.addActor(ptr); + else + mActivators.addActivator(ptr); } void MechanicsManager::remove(const MWWorld::Ptr& ptr) @@ -194,10 +194,10 @@ namespace MWMechanics void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.updateActivator(old, ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); + else + mActivators.updateActivator(old, ptr); } @@ -656,17 +656,17 @@ namespace MWMechanics void MechanicsManager::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.playAnimationGroup(ptr, groupName, mode, number); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); + else + mActivators.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - mActivators.skipAnimation(ptr); - else + if(MWWorld::Class::get(ptr).isActor()) mActors.skipAnimation(ptr); + else + mActivators.skipAnimation(ptr); } } From 04aeb3dd07f53f4cb3484287f5a73399de78ad63 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 15:29:41 -0700 Subject: [PATCH 0194/1537] Rename Mechanics' Activators to Objects --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwmechanics/activators.cpp | 81 ------------------- apps/openmw/mwmechanics/activators.hpp | 45 ----------- .../mwmechanics/mechanicsmanagerimp.cpp | 14 ++-- .../mwmechanics/mechanicsmanagerimp.hpp | 4 +- apps/openmw/mwmechanics/objects.cpp | 81 +++++++++++++++++++ apps/openmw/mwmechanics/objects.hpp | 45 +++++++++++ 7 files changed, 136 insertions(+), 136 deletions(-) delete mode 100644 apps/openmw/mwmechanics/activators.cpp delete mode 100644 apps/openmw/mwmechanics/activators.hpp create mode 100644 apps/openmw/mwmechanics/objects.cpp create mode 100644 apps/openmw/mwmechanics/objects.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index da8d474396..beb0b9aadf 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -63,7 +63,7 @@ add_openmw_dir (mwclass ) add_openmw_dir (mwmechanics - mechanicsmanagerimp stat character creaturestats magiceffects movement actors activators + mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects drawstate spells activespells npcstats aipackage aisequence alchemy aiwander aitravel aifollow aiescort aiactivate repair enchanting ) diff --git a/apps/openmw/mwmechanics/activators.cpp b/apps/openmw/mwmechanics/activators.cpp deleted file mode 100644 index cbc3802995..0000000000 --- a/apps/openmw/mwmechanics/activators.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "activators.hpp" - -#include - -#include "movement.hpp" - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - -namespace MWMechanics -{ - -Activators::Activators() -{ -} - -void Activators::addActivator(const MWWorld::Ptr& ptr) -{ - MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); - if(anim != NULL) - mActivators.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); -} - -void Activators::removeActivator (const MWWorld::Ptr& ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - mActivators.erase(iter); -} - -void Activators::updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(old); - if(iter != mActivators.end()) - { - CharacterController ctrl = iter->second; - mActivators.erase(iter); - - ctrl.updatePtr(ptr); - mActivators.insert(std::make_pair(ptr, ctrl)); - } -} - -void Activators::dropActivators (const MWWorld::Ptr::CellStore *cellStore) -{ - PtrControllerMap::iterator iter = mActivators.begin(); - while(iter != mActivators.end()) - { - if(iter->first.getCell()==cellStore) - mActivators.erase(iter++); - else - ++iter; - } -} - -void Activators::update(float duration, bool paused) -{ - if(!paused) - { - for(PtrControllerMap::iterator iter(mActivators.begin());iter != mActivators.end();++iter) - { - Movement movement; - iter->second.update(duration, movement); - } - } -} - -void Activators::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - iter->second.playGroup(groupName, mode, number); -} -void Activators::skipAnimation(const MWWorld::Ptr& ptr) -{ - PtrControllerMap::iterator iter = mActivators.find(ptr); - if(iter != mActivators.end()) - iter->second.skipAnim(); -} - -} diff --git a/apps/openmw/mwmechanics/activators.hpp b/apps/openmw/mwmechanics/activators.hpp deleted file mode 100644 index 137674a57a..0000000000 --- a/apps/openmw/mwmechanics/activators.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATRS_H - -#include -#include - -#include "character.hpp" - -namespace MWWorld -{ - class Ptr; - class CellStore; -} - -namespace MWMechanics -{ - class Activators - { - typedef std::map PtrControllerMap; - PtrControllerMap mActivators; - - public: - Activators(); - - void addActivator (const MWWorld::Ptr& ptr); - ///< Register an animated activator - - void removeActivator (const MWWorld::Ptr& ptr); - ///< Deregister an activator - - void updateActivator(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); - ///< Updates an activator with a new Ptr - - void dropActivators (const MWWorld::CellStore *cellStore); - ///< Deregister all activators in the given cell. - - void update (float duration, bool paused); - ///< Update activator animations - - void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); - void skipAnimation(const MWWorld::Ptr& ptr); - }; -} - -#endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 0af7a46655..c8d8279210 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -181,7 +181,7 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.addActor(ptr); else - mActivators.addActivator(ptr); + mObjects.addObject(ptr); } void MechanicsManager::remove(const MWWorld::Ptr& ptr) @@ -189,7 +189,7 @@ namespace MWMechanics if(ptr == mWatched) mWatched = MWWorld::Ptr(); mActors.removeActor(ptr); - mActivators.removeActivator(ptr); + mObjects.removeObject(ptr); } void MechanicsManager::updateCell(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) @@ -197,7 +197,7 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.updateActor(old, ptr); else - mActivators.updateActivator(old, ptr); + mObjects.updateObject(old, ptr); } @@ -207,7 +207,7 @@ namespace MWMechanics mWatched = MWWorld::Ptr(); mActors.dropActors(cellStore); - mActivators.dropActivators(cellStore); + mObjects.dropObjects(cellStore); } @@ -319,7 +319,7 @@ namespace MWMechanics } mActors.update(duration, paused); - mActivators.update(duration, paused); + mObjects.update(duration, paused); } void MechanicsManager::restoreDynamicStats() @@ -659,14 +659,14 @@ namespace MWMechanics if(MWWorld::Class::get(ptr).isActor()) mActors.playAnimationGroup(ptr, groupName, mode, number); else - mActivators.playAnimationGroup(ptr, groupName, mode, number); + mObjects.playAnimationGroup(ptr, groupName, mode, number); } void MechanicsManager::skipAnimation(const MWWorld::Ptr& ptr) { if(MWWorld::Class::get(ptr).isActor()) mActors.skipAnimation(ptr); else - mActivators.skipAnimation(ptr); + mObjects.skipAnimation(ptr); } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 5ad8705719..4b8d42cd30 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -7,7 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" -#include "activators.hpp" +#include "objects.hpp" #include "actors.hpp" namespace Ogre @@ -31,7 +31,7 @@ namespace MWMechanics bool mClassSelected; bool mRaceSelected; - Activators mActivators; + Objects mObjects; Actors mActors; void buildPlayer(); diff --git a/apps/openmw/mwmechanics/objects.cpp b/apps/openmw/mwmechanics/objects.cpp new file mode 100644 index 0000000000..22b996a839 --- /dev/null +++ b/apps/openmw/mwmechanics/objects.cpp @@ -0,0 +1,81 @@ +#include "objects.hpp" + +#include + +#include "movement.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWMechanics +{ + +Objects::Objects() +{ +} + +void Objects::addObject(const MWWorld::Ptr& ptr) +{ + MWRender::Animation *anim = MWBase::Environment::get().getWorld()->getAnimation(ptr); + if(anim != NULL) + mObjects.insert(std::make_pair(ptr, CharacterController(ptr, anim, CharState_Idle, true))); +} + +void Objects::removeObject(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + mObjects.erase(iter); +} + +void Objects::updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr &ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(old); + if(iter != mObjects.end()) + { + CharacterController ctrl = iter->second; + mObjects.erase(iter); + + ctrl.updatePtr(ptr); + mObjects.insert(std::make_pair(ptr, ctrl)); + } +} + +void Objects::dropObjects (const MWWorld::Ptr::CellStore *cellStore) +{ + PtrControllerMap::iterator iter = mObjects.begin(); + while(iter != mObjects.end()) + { + if(iter->first.getCell()==cellStore) + mObjects.erase(iter++); + else + ++iter; + } +} + +void Objects::update(float duration, bool paused) +{ + if(!paused) + { + for(PtrControllerMap::iterator iter(mObjects.begin());iter != mObjects.end();++iter) + { + Movement movement; + iter->second.update(duration, movement); + } + } +} + +void Objects::playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second.playGroup(groupName, mode, number); +} +void Objects::skipAnimation(const MWWorld::Ptr& ptr) +{ + PtrControllerMap::iterator iter = mObjects.find(ptr); + if(iter != mObjects.end()) + iter->second.skipAnim(); +} + +} diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp new file mode 100644 index 0000000000..6f111985c8 --- /dev/null +++ b/apps/openmw/mwmechanics/objects.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWMECHANICS_ACTIVATORS_H +#define GAME_MWMECHANICS_ACTOVATRS_H + +#include +#include + +#include "character.hpp" + +namespace MWWorld +{ + class Ptr; + class CellStore; +} + +namespace MWMechanics +{ + class Objects + { + typedef std::map PtrControllerMap; + PtrControllerMap mObjects; + + public: + Objects(); + + void addObject (const MWWorld::Ptr& ptr); + ///< Register an animated object + + void removeObject (const MWWorld::Ptr& ptr); + ///< Deregister an object + + void updateObject(const MWWorld::Ptr &old, const MWWorld::Ptr& ptr); + ///< Updates an object with a new Ptr + + void dropObjects(const MWWorld::CellStore *cellStore); + ///< Deregister all objects in the given cell. + + void update(float duration, bool paused); + ///< Update object animations + + void playAnimationGroup(const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number); + void skipAnimation(const MWWorld::Ptr& ptr); + }; +} + +#endif From d0703efd69ac5d7e0e8874d19005d2acdf2d9772 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 16:12:02 -0700 Subject: [PATCH 0195/1537] Another place to check the class' isActor method --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 7aff2e1d0c..02a5aa1006 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -111,17 +111,17 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setController(this); getStateInfo(mState, &mCurrentGroup); - if(ptr.getTypeName() == typeid(ESM::Activator).name()) - { - /* Don't accumulate with activators (they don't get moved). */ - mAnimation->setAccumulation(Ogre::Vector3::ZERO); - } - else + if(MWWorld::Class::get(mPtr).isActor()) { /* Accumulate along X/Y only for now, until we can figure out how we should * handle knockout and death which moves the character down. */ mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); } + else + { + /* Don't accumulate with non-actors. */ + mAnimation->setAccumulation(Ogre::Vector3(0.0f)); + } if(mAnimation->hasAnimation(mCurrentGroup)) mAnimation->play(mCurrentGroup, "stop", "stop", loop); } From f976eb5bd8f3a083f54adde1dab4726a923a9ad5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 31 Mar 2013 17:31:52 -0700 Subject: [PATCH 0196/1537] Improve mouselook scaling --- apps/openmw/mwinput/inputmanagerimp.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index e514638bb4..74d581b811 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -521,11 +521,13 @@ namespace MWInput { resetIdleTime(); - float x = arg.state.X.rel * mCameraSensitivity * 0.2f; - float y = arg.state.Y.rel * mCameraSensitivity * 0.2f * (mInvertY ? -1 : 1) * mUIYMultiplier; + float x = arg.state.X.rel * (1.0f/256.0f) * mCameraSensitivity; + float y = arg.state.Y.rel * (1.0f/256.0f) * mCameraSensitivity * mCameraYMultiplier * (mInvertY ? -1 : 1); + float scale = MWBase::Environment::get().getFrameDuration(); + if(scale <= 0.0f) scale = 1.0f; - mPlayer.setYaw(x); - mPlayer.setPitch(-y); + mPlayer.setYaw(x/scale); + mPlayer.setPitch(-y/scale); if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); From 26db983599daee021e2608cf37eba34254f75892 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Apr 2013 10:46:08 +0200 Subject: [PATCH 0197/1537] minor fix --- apps/openmw/mwmechanics/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 6f111985c8..3a2e51644e 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATRS_H +#define GAME_MWMECHANICS_ACTOVATORS_H #include #include From 47cc945ef47e646e29a2f49d997ec8b0ba274fd4 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 12:38:13 +0000 Subject: [PATCH 0198/1537] more refactoring --- apps/openmw/mwmechanics/aitravel.cpp | 4 ++-- apps/openmw/mwmechanics/pathfinding.cpp | 17 ++++++++++++----- apps/openmw/mwmechanics/pathfinding.hpp | 5 ++++- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index df6a38bb03..b1a4cd0a69 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -59,7 +59,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) } } - if(!mPathFinder.mIsPathConstructed ||cellChange) + if(!mPathFinder.isPathConstructed() ||cellChange) { cellX = actor.getCell()->mCell->mData.mX; cellY = actor.getCell()->mCell->mData.mY; @@ -81,7 +81,7 @@ bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) dest.mY = pos.pos[1]; dest.mZ = pos.pos[2]; - mPathFinder.findPath(start,dest,pathgrid,xCell,yCell); + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 9b76082b48..fdac50ddac 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -118,7 +118,7 @@ namespace MWMechanics return graph; } - std::list getPath(PointID start,PointID end,PathGridGraph graph){ + std::list findPath(PointID start,PointID end,PathGridGraph graph){ std::vector p(boost::num_vertices(graph)); std::vector d(boost::num_vertices(graph)); std::list shortest_path; @@ -149,7 +149,7 @@ namespace MWMechanics mIsPathConstructed = false; } - std::list PathFinder::findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void PathFinder::buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell,float yCell) { int start = getClosestPoint(pathGrid,startPoint.mX - xCell,startPoint.mY - yCell,startPoint.mZ); @@ -158,13 +158,11 @@ namespace MWMechanics if(start != -1 && end != -1) { PathGridGraph graph = buildGraph(pathGrid,xCell,yCell); - mPath = getPath(start,end,graph); + mPath = findPath(start,end,graph); } mPath.push_back(endPoint); mIsPathConstructed = true; - - return mPath; } float PathFinder::getZAngleToNext(float x,float y,float z) @@ -198,4 +196,13 @@ namespace MWMechanics } return false; } + + std::list PathFinder::getPath() + { + return mPath; + } + bool PathFinder::isPathConstructed() + { + return mIsPathConstructed; + } } \ No newline at end of file diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 200b191259..b1bbab37ab 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -11,13 +11,16 @@ namespace MWMechanics public: PathFinder(); - std::list findPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, + void buildPath(ESM::Pathgrid::Point startPoint,ESM::Pathgrid::Point endPoint, const ESM::Pathgrid* pathGrid,float xCell = 0,float yCell = 0); bool checkIfNextPointReached(float x,float y,float z);//returns true if the last point of the path has been reached. float getZAngleToNext(float x,float y,float z); + std::list getPath(); + bool isPathConstructed(); + private: std::list mPath; bool mIsPathConstructed; }; From 1bff6ed872f9deb860682fae7e398c8778433292 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 1 Apr 2013 17:12:47 +0200 Subject: [PATCH 0199/1537] Enchaning values import, fixed constness --- apps/openmw/mwmechanics/enchanting.cpp | 46 ++++++++++++++------------ apps/openmw/mwmechanics/enchanting.hpp | 22 ++++++------ 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index ba4e46de79..d86f7c1511 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -29,7 +29,7 @@ namespace MWMechanics } } - void Enchanting::setNewItemName(std::string s) + void Enchanting::setNewItemName(const std::string& s) { mNewItemName=s; } @@ -39,7 +39,7 @@ namespace MWMechanics mEffectList=effectList; } - int Enchanting::getEnchantType() + int Enchanting::getEnchantType() const { return mEnchantType; } @@ -49,30 +49,31 @@ namespace MWMechanics mSoulGemPtr=soulGem; } - int Enchanting::create() + bool Enchanting::create() { - mEnchantment.mData.mCharge = getGemCharge(); + ESM::Enchantment enchantment; + enchantment.mData.mCharge = getGemCharge(); mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { if(getEnchantChance() (RAND_MAX)*100) - return 0; + return false; MWWorld::Class::get (mEnchanter).skillUsageSucceeded (mEnchanter, ESM::Skill::Enchant, 1); } if(mEnchantType==3) { - mEnchantment.mData.mCharge=0; + enchantment.mData.mCharge=0; } - mEnchantment.mData.mType = mEnchantType; - mEnchantment.mData.mCost = getEnchantCost(); - mEnchantment.mEffects = mEffectList; + enchantment.mData.mType = mEnchantType; + enchantment.mData.mCost = getEnchantCost(); + enchantment.mEffects = mEffectList; - const ESM::Enchantment *enchantment = MWBase::Environment::get().getWorld()->createRecord (mEnchantment); + const ESM::Enchantment *enchantmentPtr = MWBase::Environment::get().getWorld()->createRecord (enchantment); - MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantment->mId, getGemCharge(), mNewItemName); + MWWorld::Class::get(mOldItemPtr).applyEnchantment(mOldItemPtr, enchantmentPtr->mId, getGemCharge(), mNewItemName); mOldItemPtr.getRefData().setCount(1); @@ -80,7 +81,7 @@ namespace MWMechanics ref.getPtr().getRefData().setCount (mOldItemCount-1); MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); - return 1; + return true; } void Enchanting::nextEnchantType() @@ -93,12 +94,13 @@ namespace MWMechanics } if ((mObjectType == typeid(ESM::Armor).name())||(mObjectType == typeid(ESM::Clothing).name())) { + int soulConstAmount = MWBase::Environment::get().getWorld()->getStore().get().find ("iSoulAmountForConstantEffect")->getInt(); switch(mEnchantType) { case 1: mEnchantType = 2; case 3: - if(getGemCharge()<400) + if(getGemCharge()getStore(); float cost = 0; @@ -138,7 +140,8 @@ namespace MWMechanics if(mEnchantType==3) { - cost1 *= 100; + int constDurationMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantDurationMult")->getFloat(); + cost1 *= constDurationMultipler; cost2 *= 2; } if(effect->mData.mFlags & ESM::MagicEffect::CastTarget) @@ -152,7 +155,7 @@ namespace MWMechanics } return cost; } - int Enchanting::getGemCharge() + int Enchanting::getGemCharge() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); if(soulEmpty()) @@ -163,20 +166,20 @@ namespace MWMechanics return soul->mData.mSoul; } - int Enchanting::getMaxEnchantValue() + int Enchanting::getMaxEnchantValue() const { if (itemEmpty()) return 0; return MWWorld::Class::get(mOldItemPtr).getEnchantmentPoints(mOldItemPtr); } - bool Enchanting::soulEmpty() + bool Enchanting::soulEmpty() const { if (mSoulGemPtr.isEmpty()) return true; return false; } - bool Enchanting::itemEmpty() + bool Enchanting::itemEmpty() const { if(mOldItemPtr.isEmpty()) return true; @@ -193,7 +196,7 @@ namespace MWMechanics mEnchanter = enchanter; } - float Enchanting::getEnchantChance() + float Enchanting::getEnchantChance() const { /* Formula from http://www.uesp.net/wiki/Morrowind:Enchant @@ -208,7 +211,8 @@ namespace MWMechanics float chance2 = 2.5 * getEnchantCost(); if(mEnchantType==3) { - chance2 *= 2; + float constantChance = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentConstantChanceMult")->getFloat(); + chance2 /= constantChance; } return (chance1-chance2); } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index 1a7dde708c..c951ae8256 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -9,7 +9,6 @@ namespace MWMechanics { class Enchanting { - MWWorld::Ptr mOldItemPtr; MWWorld::Ptr mSoulGemPtr; MWWorld::Ptr mEnchanter; @@ -19,7 +18,6 @@ namespace MWMechanics bool mSelfEnchanting; ESM::EffectList mEffectList; - ESM::Enchantment mEnchantment; std::string mNewItemName; std::string mObjectType; @@ -31,18 +29,18 @@ namespace MWMechanics void setEnchanter(MWWorld::Ptr enchanter); void setSelfEnchanting(bool selfEnchanting); void setOldItem(MWWorld::Ptr oldItem); - void setNewItemName(std::string s); + void setNewItemName(const std::string& s); void setEffect(ESM::EffectList effectList); void setSoulGem(MWWorld::Ptr soulGem); - int create(); - void nextEnchantType(); - int getEnchantType(); - int getEnchantCost(); - int getMaxEnchantValue(); - int getGemCharge(); - float getEnchantChance(); - bool soulEmpty(); - bool itemEmpty(); + bool create(); //Return true if created, false if failed. + void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) + int getEnchantType() const; + int getEnchantCost() const; + int getMaxEnchantValue() const; + int getGemCharge() const; + float getEnchantChance() const; + bool soulEmpty() const; //Return true if empty + bool itemEmpty() const; //Return true if empty }; } #endif From 9dbd024076efabe5e3a109e359495bb9f7c75cee Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 1 Apr 2013 17:30:54 +0200 Subject: [PATCH 0200/1537] another minor fix --- apps/openmw/mwmechanics/objects.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 3a2e51644e..7b1185a29a 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -1,5 +1,5 @@ #ifndef GAME_MWMECHANICS_ACTIVATORS_H -#define GAME_MWMECHANICS_ACTOVATORS_H +#define GAME_MWMECHANICS_ACTIVATORS_H #include #include From 2be9405c96056fc6a12b2c5d4d048e0d74ca3d6d Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 15:44:08 +0000 Subject: [PATCH 0201/1537] the sgn function is no longer in the global namespace --- apps/openmw/mwmechanics/aitravel.cpp | 157 ++++++++++++++------------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index b1a4cd0a69..4aca5f3d49 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,92 +13,95 @@ #include #include "boost/tuple/tuple.hpp" -MWMechanics::AiTravel::AiTravel(float x, float y, float z) - : mX(x),mY(y),mZ(z),mPathFinder() +namespace MWMechanics { -} -MWMechanics::AiTravel * MWMechanics::AiTravel::clone() const -{ - return new AiTravel(*this); -} - -float sgn(float a) -{ - if(a>0) return 1.; - else return -1.; -} - -bool MWMechanics::AiTravel::execute (const MWWorld::Ptr& actor) -{ - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - - ESM::Position pos = actor.getRefData().getPosition(); - bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + AiTravel::AiTravel(float x, float y, float z) + : mX(x),mY(y),mZ(z),mPathFinder() { - int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + } + + AiTravel * AiTravel::clone() const + { + return new AiTravel(*this); + } + + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } + + bool AiTravel::execute (const MWWorld::Ptr& actor) + { + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + + ESM::Position pos = actor.getRefData().getPosition(); + bool cellChange = actor.getCell()->mCell->mData.mX != cellX || actor.getCell()->mCell->mData.mY != cellY; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(actor.getCell()->mCell->mData.mX != player.getCell()->mCell->mData.mX) + { + int sideX = sgn(actor.getCell()->mCell->mData.mX - player.getCell()->mCell->mData.mX); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + { + int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); + //check if actor is near the border of an inactive cell. If so, disable aitravel. + if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) + { + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + return true; + } + } + + if(!mPathFinder.isPathConstructed() ||cellChange) + { + cellX = actor.getCell()->mCell->mData.mX; + cellY = actor.getCell()->mCell->mData.mY; + float xCell = 0; + float yCell = 0; + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } + + ESM::Pathgrid::Point dest; + dest.mX = mX; + dest.mY = mY; + dest.mZ = mZ; + + ESM::Pathgrid::Point start; + dest.mX = pos.pos[0]; + dest.mY = pos.pos[1]; + dest.mZ = pos.pos[2]; + + mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); + } + if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; return true; } + + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); + MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); + MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + + return false; } - if(actor.getCell()->mCell->mData.mY != player.getCell()->mCell->mData.mY) + + int AiTravel::getTypeId() const { - int sideY = sgn(actor.getCell()->mCell->mData.mY - player.getCell()->mCell->mData.mY); - //check if actor is near the border of an inactive cell. If so, disable aitravel. - if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } + return 1; } - if(!mPathFinder.isPathConstructed() ||cellChange) - { - cellX = actor.getCell()->mCell->mData.mX; - cellY = actor.getCell()->mCell->mData.mY; - float xCell = 0; - float yCell = 0; - if (actor.getCell()->mCell->isExterior()) - { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; - } - - ESM::Pathgrid::Point dest; - dest.mX = mX; - dest.mY = mY; - dest.mZ = mZ; - - ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; - - mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); - } - if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) - { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; - return true; - } - - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); - MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; - - return false; } - -int MWMechanics::AiTravel::getTypeId() const -{ - return 1; -} - - From 20af7d89a2550a9873dd0ab03d5240af25f3b0f7 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:30:40 +0000 Subject: [PATCH 0202/1537] post master-merge fixes. Looks a little odd. --- apps/openmw/mwmechanics/aitravel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 4aca5f3d49..dd769f91c4 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -47,7 +47,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideX*(pos.pos[0] - actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE) > sideX*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -57,7 +57,7 @@ namespace MWMechanics //check if actor is near the border of an inactive cell. If so, disable aitravel. if(sideY*(pos.pos[1] - actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE) > sideY*(ESM::Land::REAL_SIZE/2. - 2000)) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } } @@ -88,13 +88,13 @@ namespace MWMechanics } if(mPathFinder.checkIfNextPointReached(pos.pos[0],pos.pos[1],pos.pos[2])) { - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 0; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; return true; } float zAngle = mPathFinder.getZAngleToNext(pos.pos[0],pos.pos[1],pos.pos[2]); MWBase::Environment::get().getWorld()->rotateObject(actor,0,0,zAngle,false); - MWWorld::Class::get(actor).getMovementSettings(actor).mForwardBackward = 1; + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; return false; } From 6a33170ca244db400d49651597ce3cc80d753723 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 1 Apr 2013 17:44:06 +0000 Subject: [PATCH 0203/1537] More bugfix, but I don't like this one. --- apps/openmw/mwmechanics/aitravel.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index dd769f91c4..25efe8fff0 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -26,7 +26,7 @@ namespace MWMechanics return new AiTravel(*this); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index fdac50ddac..1d98674ef5 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -23,7 +23,7 @@ namespace MWMechanics return sqrt(float(a.mX - b.mX)*(a.mX - b.mX)+(a.mY - b.mY)*(a.mY - b.mY)+(a.mZ - b.mZ)*(a.mZ - b.mZ)); } - float sgn(float a) + static float sgn(float a) { if(a>0) return 1.; else return -1.; From d25c838e1d3c5f9aabfc4c41e1482e835c6c034e Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 11:42:29 +0200 Subject: [PATCH 0204/1537] Bugfix #646 --- apps/openmw/mwworld/actionequip.cpp | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index afbb505f22..513182a2dc 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -108,6 +108,46 @@ namespace MWWorld } + //Disable twohanded when shield equipped, shield when twohanded equipped + if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + invStore.equip(*slot, it); + + if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + } + } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + } + } + // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) { From c71edb613d12e3b46bd4d0e998e054bbcf4cc330 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 12:00:45 +0200 Subject: [PATCH 0205/1537] added faction table --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 3 +++ components/esm/loadfact.cpp | 25 +++++++++++++++++++++++-- components/esm/loadfact.hpp | 3 +++ 9 files changed, 67 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 7b3e667715..825e29a232 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -57,10 +57,15 @@ CSMWorld::Data::Data() mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); + mFactions.addColumn (new StringIdColumn); + mFactions.addColumn (new RecordStateColumn); + mFactions.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); + addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); } CSMWorld::Data::~Data() @@ -99,6 +104,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSkills() return mSkills; } +const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const +{ + return mFactions; +} + +CSMWorld::IdCollection& CSMWorld::Data::getFactions() +{ + return mFactions; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -137,6 +152,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_GMST: mGmsts.load (reader, base); break; case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; + case ESM::REC_FACT: mFactions.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7baf03259e..1e2894774a 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -24,6 +25,7 @@ namespace CSMWorld IdCollection mGmsts; IdCollection mSkills; IdCollection mClasses; + IdCollection mFactions; std::vector mModels; std::map mModelIndex; @@ -52,6 +54,10 @@ namespace CSMWorld IdCollection& getSkills(); + const IdCollection& getFactions() const; + + IdCollection& getFactions(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index a85b30c2a8..985cab0d4c 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -21,6 +21,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -31,6 +32,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Gmst, "Game Setting" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 4c4d95654b..0190467c4b 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -41,7 +41,9 @@ namespace CSMWorld Type_Skills, Type_Skill, Type_Classes, - Type_Class + Type_Class, + Type_Factions, + Type_Faction }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 2ef66593f7..3c4bc3b047 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -94,6 +94,10 @@ void CSVDoc::View::setupWorldMenu() connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView())); world->addAction (classes); + QAction *factions = new QAction (tr ("Factions"), this); + connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); + world->addAction (factions); + mVerify = new QAction (tr ("&Verify"), this); connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); world->addAction (mVerify); @@ -262,6 +266,11 @@ void CSVDoc::View::addClassesSubView() addSubView (CSMWorld::UniversalId::Type_Classes); } +void CSVDoc::View::addFactionsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Factions); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index bc8e8fc26d..03905430a8 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -119,6 +119,8 @@ namespace CSVDoc void addSkillsSubView(); void addClassesSubView(); + + void addFactionsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 5d715ea21e..cbfbf6b464 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -20,6 +20,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Classes, new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Factions, + new CSVDoc::SubViewFactoryWithCreateFlag (true)); + // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); } \ No newline at end of file diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 6ea66977d5..50fb94bbb7 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -33,7 +33,7 @@ void Faction::load(ESMReader &esm) void Faction::save(ESMWriter &esm) { esm.writeHNCString("FNAM", mName); - + for (int i = 0; i < 10; i++) { if (mRanks[i].empty()) @@ -43,7 +43,7 @@ void Faction::save(ESMWriter &esm) } esm.writeHNT("FADT", mData, 240); - + for (std::vector::iterator it = mReactions.begin(); it != mReactions.end(); ++it) { esm.writeHNString("ANAM", it->mFaction); @@ -51,4 +51,25 @@ void Faction::save(ESMWriter &esm) } } + void Faction::blank() + { + mName.clear(); + mData.mAttribute1 = mData.mAttribute2 = 0; + mData.mUnknown = -1; + mData.mIsHidden = 0; + + for (int i=0; i<10; ++i) + { + mData.mRankData[i].mAttribute1 = mData.mRankData[i].mAttribute2 = 0; + mData.mRankData[i].mSkill1 = mData.mRankData[i].mSkill2 = 0; + mData.mRankData[i].mFactReaction = 0; + + mRanks[i].clear(); + } + + for (int i=0; i<6; ++i) + mData.mSkillID[i] = 0; + + mReactions.clear(); + } } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index 49898b1cf2..a2ba688c01 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -58,6 +58,9 @@ struct Faction void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From f9f520df34373dc585d7bf695362564a6b7fe3b7 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 13:59:45 +0200 Subject: [PATCH 0206/1537] adjusted faction record to increase consistency with other records --- apps/esmtool/record.cpp | 14 +++++++------- apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 6 +++--- apps/openmw/mwmechanics/npcstats.cpp | 2 +- components/esm/loadclas.cpp | 19 +++++++++++++++++++ components/esm/loadclas.hpp | 6 ++++++ components/esm/loadfact.cpp | 21 +++++++++++++++++++-- components/esm/loadfact.hpp | 10 ++++++++-- 8 files changed, 65 insertions(+), 17 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index de3a175106..8f77e4b445 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -679,14 +679,14 @@ void Record::print() std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; if (mData.mData.mUnknown != -1) std::cout << " Unknown: " << mData.mData.mUnknown << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute1) - << " (" << mData.mData.mAttribute1 << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute2) - << " (" << mData.mData.mAttribute2 << ")" << std::endl; + std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttributes[0]) + << " (" << mData.mData.mAttributes[0] << ")" << std::endl; + std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttributes[1]) + << " (" << mData.mData.mAttributes[1] << ")" << std::endl; for (int i = 0; i != 6; i++) - if (mData.mData.mSkillID[i] != -1) - std::cout << " Skill: " << skillLabel(mData.mData.mSkillID[i]) - << " (" << mData.mData.mSkillID[i] << ")" << std::endl; + if (mData.mData.mSkills[i] != -1) + std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) + << " (" << mData.mData.mSkills[i] << ")" << std::endl; for (int i = 0; i != 10; i++) if (mData.mRanks[i] != "") { diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index f7e9529568..ddb15d423d 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -569,8 +569,8 @@ bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& ac MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); - return stats.getAttribute (faction.mData.mAttribute1).getBase()>=faction.mData.mRankData[rank].mAttribute1 && - stats.getAttribute (faction.mData.mAttribute2).getBase()>=faction.mData.mRankData[rank].mAttribute2; + return stats.getAttribute (faction.mData.mAttributes[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttributes[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; } bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 0fa4127b55..86019fa28d 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -500,8 +500,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute1); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute2); + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttributes[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttributes[1]); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) @@ -511,7 +511,7 @@ void StatsWindow::updateSkillArea() text += "\n#BF9959"; for (int i=0; i<6; ++i) { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; if (i<5) text += ", "; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index b9aee6abf3..7216e8fe0e 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -334,7 +334,7 @@ bool MWMechanics::NpcStats::hasSkillsForRank (const std::string& factionId, int std::vector skills; for (int i=0; i<6; ++i) - skills.push_back (static_cast (getSkill (faction.mData.mSkillID[i]).getModified())); + skills.push_back (static_cast (getSkill (faction.mData.mSkills[i]).getModified())); std::sort (skills.begin(), skills.end()); diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp index d9f367fd63..bdc4614625 100644 --- a/components/esm/loadclas.cpp +++ b/components/esm/loadclas.cpp @@ -1,5 +1,7 @@ #include "loadclas.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" @@ -18,6 +20,23 @@ const char *Class::sGmstSpecializationIds[3] = { "sSpecializationStealth" }; + + int& Class::CLDTstruct::getSkill (int index, bool major) + { + if (index<0 || index>=5) + throw std::logic_error ("skill index out of range"); + + return mSkills[index][major ? 1 : 0]; + } + + int Class::CLDTstruct::getSkill (int index, bool major) const + { + if (index<0 || index>=5) + throw std::logic_error ("skill index out of range"); + + return mSkills[index][major ? 1 : 0]; + } + void Class::load(ESMReader &esm) { mName = esm.getHNString("FNAM"); diff --git a/components/esm/loadclas.hpp b/components/esm/loadclas.hpp index ac596af32c..4f85e6ee8b 100644 --- a/components/esm/loadclas.hpp +++ b/components/esm/loadclas.hpp @@ -58,6 +58,12 @@ struct Class // I have no idea how to autocalculate these items... int mCalc; + + int& getSkill (int index, bool major); + ///< Throws an exception for invalid values of \a index. + + int getSkill (int index, bool major) const; + ///< Throws an exception for invalid values of \a index. }; // 60 bytes std::string mId, mName, mDescription; diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 50fb94bbb7..12a76f1ade 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -1,10 +1,27 @@ #include "loadfact.hpp" +#include + #include "esmreader.hpp" #include "esmwriter.hpp" namespace ESM { + int& Faction::FADTstruct::getSkill (int index, bool ignored) + { + if (index<0 || index>=6) + throw std::logic_error ("skill index out of range"); + + return mSkills[index]; + } + + int Faction::FADTstruct::getSkill (int index, bool ignored) const + { + if (index<0 || index>=6) + throw std::logic_error ("skill index out of range"); + + return mSkills[index]; + } void Faction::load(ESMReader &esm) { @@ -54,7 +71,7 @@ void Faction::save(ESMWriter &esm) void Faction::blank() { mName.clear(); - mData.mAttribute1 = mData.mAttribute2 = 0; + mData.mAttributes[0] = mData.mAttributes[1] = 0; mData.mUnknown = -1; mData.mIsHidden = 0; @@ -68,7 +85,7 @@ void Faction::save(ESMWriter &esm) } for (int i=0; i<6; ++i) - mData.mSkillID[i] = 0; + mData.mSkills[i] = 0; mReactions.clear(); } diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index a2ba688c01..edc4640bb1 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -34,13 +34,19 @@ struct Faction struct FADTstruct { // Which attributes we like - int mAttribute1, mAttribute2; + int mAttributes[2]; RankData mRankData[10]; - int mSkillID[6]; // IDs of skills this faction require + int mSkills[6]; // IDs of skills this faction require int mUnknown; // Always -1? int mIsHidden; // 1 - hidden from player + + int& getSkill (int index, bool ignored = false); + ///< Throws an exception for invalid values of \a index. + + int getSkill (int index, bool ignored = false) const; + ///< Throws an exception for invalid values of \a index. }; // 240 bytes FADTstruct mData; From ec6bdbeb40dd3641233ac5e22b4557ee795affe0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 14:04:13 +0200 Subject: [PATCH 0207/1537] added skill columns to faction table --- apps/opencs/model/world/columns.hpp | 8 ++++---- apps/opencs/model/world/data.cpp | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index cbcddd972d..9345df0d20 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -347,15 +347,15 @@ namespace CSMWorld int mIndex; bool mMajor; - SkillsColumn (int index, bool major) - : Column ((major ? "Major Skill #" : "Minor Skill #")+ + SkillsColumn (int index, bool typePrefix = false, bool major = false) + : Column ((typePrefix ? (major ? "Major Skill #" : "Minor Skill #") : "Skill #")+ boost::lexical_cast (index), ColumnBase::Display_String), mIndex (index), mMajor (major) {} virtual QVariant get (const Record& record) const { - int skill = record.get().mData.mSkills[mIndex][mMajor ? 1 : 0]; + int skill = record.get().mData.getSkill (mIndex, mMajor); return QString::fromUtf8 (ESM::Skill::indexToId (skill).c_str()); } @@ -373,7 +373,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - record2.mData.mSkills[mIndex][mMajor ? 1 : 0] = index; + record2.mData.getSkill (mIndex, mMajor) = index; record.setModified (record2); } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 825e29a232..23a1eb91b9 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -51,15 +51,17 @@ CSMWorld::Data::Data() mClasses.addColumn (new AttributesColumn (1)); mClasses.addColumn (new SpecialisationColumn); for (int i=0; i<5; ++i) - mClasses.addColumn (new SkillsColumn (i, true)); + mClasses.addColumn (new SkillsColumn (i, true, true)); for (int i=0; i<5; ++i) - mClasses.addColumn (new SkillsColumn (i, false)); + mClasses.addColumn (new SkillsColumn (i, true, false)); mClasses.addColumn (new PlayableColumn); mClasses.addColumn (new DescriptionColumn); mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + for (int i=0; i<6; ++i) + mFactions.addColumn (new SkillsColumn (i)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 900c2cfa81b629a74fcb3ce112fbbf1578217c3a Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 14:08:59 +0200 Subject: [PATCH 0208/1537] Minor bugfix #646 change --- apps/openmw/mwworld/actionequip.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 513182a2dc..9a44a99791 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -111,8 +111,6 @@ namespace MWWorld //Disable twohanded when shield equipped, shield when twohanded equipped if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - invStore.equip(*slot, it); - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) { if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || From 384c88182dfa5ab54e215bafa99edc8cfed6a867 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 14:15:22 +0200 Subject: [PATCH 0209/1537] dealing with unset attribute fields --- apps/opencs/view/doc/viewmanager.cpp | 2 +- apps/opencs/view/world/enumdelegate.cpp | 5 ++++- apps/opencs/view/world/enumdelegate.hpp | 3 ++- components/esm/loadskil.cpp | 15 +++++++++------ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index bc87728945..3be7228b31 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -61,7 +61,7 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) new CSVWorld::EnumDelegateFactory (sSpecialisations)); mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, - new CSVWorld::EnumDelegateFactory (sAttributes)); + new CSVWorld::EnumDelegateFactory (sAttributes, true)); } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 0dd0a1d594..b1e9f72865 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -92,10 +92,13 @@ void CSVWorld::EnumDelegate::paint (QPainter *painter, const QStyleOptionViewIte CSVWorld::EnumDelegateFactory::EnumDelegateFactory() {} -CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names) +CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const char **names, bool allowNone) { assert (names); + if (allowNone) + add (-1, ""); + for (int i=0; names[i]; ++i) add (i, names[i]); } diff --git a/apps/opencs/view/world/enumdelegate.hpp b/apps/opencs/view/world/enumdelegate.hpp index 752ed5be72..58f19ff782 100644 --- a/apps/opencs/view/world/enumdelegate.hpp +++ b/apps/opencs/view/world/enumdelegate.hpp @@ -47,8 +47,9 @@ namespace CSVWorld EnumDelegateFactory(); - EnumDelegateFactory (const char **names); + EnumDelegateFactory (const char **names, bool allowNone = false); ///< \param names Array of char pointer with a 0-pointer as end mark + /// \param allowNone Use value of -1 for "none selected" (empty string) virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; ///< The ownership of the returned CommandDelegate is transferred to the caller. diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index b7259db94e..b57645f3b8 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -127,15 +127,18 @@ void Skill::save(ESMWriter &esm) { std::ostringstream stream; - stream << "#"; + if (index!=-1) + { + stream << "#"; - if (index<10) - stream << "0"; + if (index<10) + stream << "0"; - stream << index; + stream << index; - if (index>=0 && index=0 && index Date: Tue, 2 Apr 2013 14:20:51 +0200 Subject: [PATCH 0210/1537] added hidden flag column to faction table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 9345df0d20..dfabaaf2cf 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -409,6 +409,31 @@ namespace CSMWorld return true; } }; + + template + struct HiddenColumn : public Column + { + HiddenColumn() : Column ("Hidden", ColumnBase::Display_Boolean) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mIsHidden!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mIsHidden = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 23a1eb91b9..13fff7f096 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,6 +60,7 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + mFactions.addColumn (new HiddenColumn); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); From 9d009af2a132823795dc949ed9b030e4a95e7a1e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 15:33:28 +0200 Subject: [PATCH 0211/1537] simplified code for sub view factory creation --- apps/opencs/view/world/subviews.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index cbfbf6b464..de36594a58 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -8,20 +8,24 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { - manager.add (CSMWorld::UniversalId::Type_Globals, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); - manager.add (CSMWorld::UniversalId::Type_Gmsts, new CSVDoc::SubViewFactoryWithCreateFlag (false)); manager.add (CSMWorld::UniversalId::Type_Skills, new CSVDoc::SubViewFactoryWithCreateFlag (false)); - manager.add (CSMWorld::UniversalId::Type_Classes, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); + static const CSMWorld::UniversalId::Type sTableTypes[] = + { + CSMWorld::UniversalId::Type_Globals, + CSMWorld::UniversalId::Type_Classes, + CSMWorld::UniversalId::Type_Factions, + + CSMWorld::UniversalId::Type_None // end marker + }; + + for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i) + manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag (true)); - manager.add (CSMWorld::UniversalId::Type_Factions, - new CSVDoc::SubViewFactoryWithCreateFlag (true)); // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); From 676a92e2e0157abe29fd898531b0c63610db0466 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 2 Apr 2013 15:47:25 +0200 Subject: [PATCH 0212/1537] moved Verify function from World menu to File menu --- apps/opencs/view/doc/view.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3c4bc3b047..83b333c04e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -41,6 +41,10 @@ void CSVDoc::View::setupFileMenu() connect (mSave, SIGNAL (triggered()), this, SLOT (save())); file->addAction (mSave); + mVerify = new QAction (tr ("&Verify"), this); + connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); + file->addAction (mVerify); + QAction *close = new QAction (tr ("&Close"), this); connect (close, SIGNAL (triggered()), this, SLOT (close())); file->addAction(close); @@ -97,10 +101,6 @@ void CSVDoc::View::setupWorldMenu() QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); world->addAction (factions); - - mVerify = new QAction (tr ("&Verify"), this); - connect (mVerify, SIGNAL (triggered()), this, SLOT (verify())); - world->addAction (mVerify); } void CSVDoc::View::setupUi() From 369cf0b4cafac002e0a0338163b95a29630f2b51 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 20:46:48 +0200 Subject: [PATCH 0213/1537] Enchanting price mechanics --- apps/openmw/mwgui/enchantingdialog.cpp | 27 ++++++++---------- apps/openmw/mwmechanics/enchanting.cpp | 38 +++++++++++++++++++++++++- apps/openmw/mwmechanics/enchanting.hpp | 2 ++ 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 0f3b8b7cb0..1ed80127d4 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -63,6 +63,8 @@ namespace MWGui mCastCost->setCaption(boost::lexical_cast(mEnchanting.getEnchantCost())); + mPrice->setCaption(boost::lexical_cast(mEnchanting.getEnchantPrice())); + switch(mEnchanting.getEnchantType()) { case 0: @@ -86,16 +88,10 @@ namespace MWGui void EnchantingDialog::startEnchanting (MWWorld::Ptr actor) { - - /*Now there's no need to use other enchanters, player is the enchanter here, - even if the enchanted object is created by NPC. Could be changed later, probably - with some price formulas */ - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - mEnchanting.setSelfEnchanting(false); - mEnchanting.setEnchanter(player); + mEnchanting.setEnchanter(actor); - mPtr = player; + mPtr = actor; startEditing (); } @@ -103,13 +99,14 @@ namespace MWGui void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Ptr gem = soulgem; mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); mPtr = player; - startEditing(); + mEnchanting.setSoulGem(gem); } void EnchantingDialog::onReferenceUnavailable () @@ -252,12 +249,6 @@ namespace MWGui return; } - if (boost::lexical_cast(mPrice->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) - { - mWindowManager.messageBox ("#{sNotifyMessage18}"); - return; - } - if (mEnchanting.soulEmpty()) { mWindowManager.messageBox ("#{sNotifyMessage52}"); @@ -279,6 +270,12 @@ namespace MWGui mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); + if (mEnchanting.getEnchantPrice() > mWindowManager.getInventoryWindow()->getPlayerGold()) + { + mWindowManager.messageBox ("#{sNotifyMessage18}"); + return; + } + int result = mEnchanting.create(); if(result==1) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d86f7c1511..a2f85fb0c4 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -3,6 +3,7 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "creaturestats.hpp" #include "npcstats.hpp" @@ -79,7 +80,10 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); ref.getPtr().getRefData().setCount (mOldItemCount-1); - MWWorld::Class::get (mEnchanter).getContainerStore (mEnchanter).add (ref.getPtr()); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); + payForEnchantment(); return true; } @@ -126,6 +130,8 @@ namespace MWMechanics float cost = 0; std::vector mEffects = mEffectList.mList; int i=mEffects.size(); + if(i<=0) + return 0; /* Formula from http://www.uesp.net/wiki/Morrowind:Enchant @@ -155,6 +161,17 @@ namespace MWMechanics } return cost; } + + int Enchanting::getEnchantPrice() const + { + if(mEnchanter.isEmpty()) + return 0; + + float priceMultipler = MWBase::Environment::get().getWorld()->getStore().get().find ("fEnchantmentValueMult")->getFloat(); + int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mEnchanter, (getEnchantCost() * priceMultipler), true); + return price; + } + int Enchanting::getGemCharge() const { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -216,4 +233,23 @@ namespace MWMechanics } return (chance1-chance2); } + + void Enchanting::payForEnchantment() const + { + MWWorld::Ptr gold; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); + + for (MWWorld::ContainerStoreIterator it = store.begin(); + it != store.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mRefID, "gold_001")) + { + gold = *it; + } + } + + gold.getRefData().setCount(gold.getRefData().getCount() - getEnchantPrice()); + } } diff --git a/apps/openmw/mwmechanics/enchanting.hpp b/apps/openmw/mwmechanics/enchanting.hpp index c951ae8256..d8a6342ac9 100644 --- a/apps/openmw/mwmechanics/enchanting.hpp +++ b/apps/openmw/mwmechanics/enchanting.hpp @@ -36,11 +36,13 @@ namespace MWMechanics void nextEnchantType(); //Set enchant type to next possible type (for mOldItemPtr object) int getEnchantType() const; int getEnchantCost() const; + int getEnchantPrice() const; int getMaxEnchantValue() const; int getGemCharge() const; float getEnchantChance() const; bool soulEmpty() const; //Return true if empty bool itemEmpty() const; //Return true if empty + void payForEnchantment() const; }; } #endif From 98727d2fb6c6ec26a5f8dabe370d9714b23d71dd Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 21:32:23 +0200 Subject: [PATCH 0214/1537] Workaround for launcher compilation problems due to bug in Qt MOC compiler. For details please see: https://forum.openmw.org/viewtopic.php?f=7&t=1451 https://bugreports.qt-project.org/browse/QTBUG-22829 Signed-off-by: Lukasz Gromanowski --- apps/launcher/maindialog.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/launcher/maindialog.hpp b/apps/launcher/maindialog.hpp index 7e818a74ab..824dff6e82 100644 --- a/apps/launcher/maindialog.hpp +++ b/apps/launcher/maindialog.hpp @@ -2,9 +2,9 @@ #define MAINDIALOG_H #include - +#ifndef Q_MOC_RUN #include - +#endif #include "settings/gamesettings.hpp" #include "settings/graphicssettings.hpp" #include "settings/launchersettings.hpp" From 7b7d3353a66fc30e6282c6d3931d012abbfa029e Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 2 Apr 2013 22:23:38 +0200 Subject: [PATCH 0215/1537] Exception for enchanting with Azura Star --- apps/openmw/mwmechanics/enchanting.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index a2f85fb0c4..45db667d26 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -54,7 +54,12 @@ namespace MWMechanics { ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + + //Exception for Azura Star, it's not destroyed after enchanting + if(mSoulGemPtr.get()->mBase->mId=="Misc_SoulGem_Azura") + mSoulGemPtr.getCellRef().mSoul=""; + else + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); if(mSelfEnchanting) { From 061fb4c482353633d2610166646a981998307a24 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:15:22 +0200 Subject: [PATCH 0216/1537] Added simple Travis CI cfg file. Added simple Travis CI configuration file for testing. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..94cf749245 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,18 @@ +language: cpp +compiler: + - clang + - gcc +before_script: + - mkdir build + - cd build + - cmake .. +branches: + only: + - master + - travis_ci_test +notifications: + recipients: + - lgromanowski+travis.ci@gmail.com + email: + on_success: change + on_failure: always From df8da0486da56835f55ab31e2aa87bfda82a50e0 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:20:59 +0200 Subject: [PATCH 0217/1537] Small changes in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 94cf749245..f2a9179f59 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,9 @@ before_script: - mkdir build - cd build - cmake .. +before_install: + - git submodule update --init --recursive +script: make branches: only: - master From cb18cf1eee9ab28ced4347aa880403972ed18dde Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:30:44 +0200 Subject: [PATCH 0218/1537] Added OpenMW dependencies into .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f2a9179f59..6e3748056c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,10 @@ before_script: - cd build - cmake .. before_install: - - git submodule update --init --recursive + - git submodule update --init --recursive + - sudo apt-add-repository ppa:openmw/deps + - sudo apt-get update -qq + - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make branches: only: From 4f19fb0cdbfa5ac3815f83133cb1d864f371274a Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:38:23 +0200 Subject: [PATCH 0219/1537] Changes in apt-add-repository line - added echo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6e3748056c..cdbabb1a1e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - cmake .. before_install: - git submodule update --init --recursive - - sudo apt-add-repository ppa:openmw/deps + - echo -e "\n" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make From f8497895149469720e56c25fc0b9b25e08e3c058 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Tue, 2 Apr 2013 23:41:24 +0200 Subject: [PATCH 0220/1537] Changes in apt-add-repository line. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cdbabb1a1e..3d3ad404c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - cmake .. before_install: - git submodule update --init --recursive - - echo -e "\n" | sudo apt-add-repository ppa:openmw/deps + - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static script: make From df0ee82a3c9f27700ee39ac5175a01fc77912b7a Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Apr 2013 23:45:32 +0200 Subject: [PATCH 0221/1537] Loose files should have priority over BSA resources. This makes texture replacers work. --- apps/openmw/engine.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index ce84b8dfe1..dad024c98e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -153,20 +153,6 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { - for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) - { - if (mFileCollections.doesExist(*archive)) - { - const std::string archivePath = mFileCollections.getPath(*archive).string(); - std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath); - } - else - { - std::cout << "Archive " << *archive << " not found" << std::endl; - } - } - const Files::PathContainer& dataDirs = mFileCollections.getPaths(); std::string dataDirectory; for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) @@ -175,6 +161,24 @@ void OMW::Engine::loadBSA() std::cout << "Data dir " << dataDirectory << std::endl; Bsa::addDir(dataDirectory, mFSStrict); } + + // BSA resources are put into a separate group. We want loose files to have priority over BSA resources, and this seems + // to be the only way to get Ogre to do just that. + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("GroupBSA"); + + for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) + { + if (mFileCollections.doesExist(*archive)) + { + const std::string archivePath = mFileCollections.getPath(*archive).string(); + std::cout << "Adding BSA archive " << archivePath << std::endl; + Bsa::addBSA(archivePath, "GroupBSA"); + } + else + { + std::cout << "Archive " << *archive << " not found" << std::endl; + } + } } // add resources directory From 73b984cc2d01ccca61cd5efeaa51f324060e69d9 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:08:24 +0200 Subject: [PATCH 0222/1537] Corrected packages names in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3d3ad404c5..75fe322990 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg-dev boost-dev libbullet libogre-static mygui-static + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev mygui-static-dev script: make branches: only: From c32f4d853e6ca6b9f5f06367ad526f911c034bfb Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:14:26 +0200 Subject: [PATCH 0223/1537] Another change in packages names in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 75fe322990..a29140b256 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev mygui-static-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev script: make branches: only: From c73209c049b4ba2776fb8c11ae91132dba8515a8 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:21:42 +0200 Subject: [PATCH 0224/1537] Added another part of dependencies, enabled building with static ogre and mygui. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a29140b256..1239f1ed0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ compiler: before_script: - mkdir build - cd build - - cmake .. + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev script: make branches: only: From 05a5cb3ae48e00d82488d2d4056a5fd906cde571 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 00:27:29 +0200 Subject: [PATCH 0225/1537] Improved responsiveness of the inventory window when resizing. --- apps/openmw/engine.cpp | 1 + apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/inventorywindow.cpp | 20 +++++++++++++++----- apps/openmw/mwgui/inventorywindow.hpp | 4 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 ++ 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index dad024c98e..948a06d471 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -66,6 +66,7 @@ bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt) { if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame); + MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame); return true; } diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4d66a77423..b271aed182 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -246,6 +246,8 @@ namespace MWBase virtual void showSoulgemDialog (MWWorld::Ptr item) = 0; + virtual void frameStarted(float dt) = 0; + virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 1943ff773a..aeab5f94aa 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -37,6 +37,7 @@ namespace MWGui , mLastXSize(0) , mLastYSize(0) , mPreview(MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()) + , mPreviewDirty(true) { static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); @@ -268,6 +269,19 @@ namespace MWGui mTrading = true; } + void InventoryWindow::doRenderUpdate () + { + if (mPreviewDirty) + { + mPreviewDirty = false; + MyGUI::IntSize size = mAvatar->getSize(); + + mPreview.update (size.width, size.height); + mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); + mAvatarImage->setImageTexture("CharacterPreview"); + } + } + void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory @@ -282,11 +296,7 @@ namespace MWGui else mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability - MyGUI::IntSize size = mAvatar->getSize(); - - mPreview.update (size.width, size.height); - mAvatarImage->setSize(MyGUI::IntSize(std::max(mAvatar->getSize().width, 512), std::max(mAvatar->getSize().height, 1024))); - mAvatarImage->setImageTexture("CharacterPreview"); + mPreviewDirty = true; mArmorRating->setCaptionWithReplacing ("#{sArmor}: " + boost::lexical_cast(static_cast(MWWorld::Class::get(mPtr).getArmorRating(mPtr)))); diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 95657672d3..fceb7ecef1 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -16,6 +16,8 @@ namespace MWGui virtual void open(); + void doRenderUpdate(); + /// start trading, disables item drag&drop void startTrade(); @@ -34,6 +36,8 @@ namespace MWGui } protected: + bool mPreviewDirty; + MyGUI::Widget* mAvatar; MyGUI::ImageBox* mAvatarImage; MyGUI::TextBox* mArmorRating; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index cf14c1f514..c975b2cdba 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1190,3 +1190,8 @@ void WindowManager::showSoulgemDialog(MWWorld::Ptr item) { mSoulgemDialog->show(item); } + +void WindowManager::frameStarted (float dt) +{ + mInventoryWindow->doRenderUpdate (); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 7a7adec27d..c14c6b2fe4 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -238,6 +238,8 @@ namespace MWGui virtual void startRepair(MWWorld::Ptr actor); virtual void startRepairItem(MWWorld::Ptr item); + virtual void frameStarted(float dt); + virtual void showSoulgemDialog (MWWorld::Ptr item); virtual void changePointer (const std::string& name); From 5a1bb21b23b1c68a1ea597ac339396a0a2704aee Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:30:43 +0200 Subject: [PATCH 0226/1537] Build dependecies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1239f1ed0e..80c3a46537 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools script: make branches: only: From 74d519d4057fe9d06c4b3b0fe3d6d1cafb074390 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:35:18 +0200 Subject: [PATCH 0227/1537] Added libois into build dependencies in .travis.yml file. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 80c3a46537..51fa23e8e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools libois-dev script: make branches: only: From 798ed642030dc059e0ab4d4963061bffb07131b6 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:40:01 +0200 Subject: [PATCH 0228/1537] Added google-mock and libopenal into build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 51fa23e8e6..003a4d8013 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev zziplib-bin libmpg123-dev libcg libav-tools libois-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev script: make branches: only: From 5957a9e037942934b30202b572ed9d8bb0cb4876 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:44:03 +0200 Subject: [PATCH 0229/1537] Added libxaw7 into dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 003a4d8013..4939ad0ec7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From e7bb3743cc491d00e036791d6f74ccf512d92286 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 00:58:59 +0200 Subject: [PATCH 0230/1537] Trying to build with Ogre shared lib . Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4939ad0ec7..d31e4afc8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,12 +5,12 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 + - cmake .. -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-static-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From f6f165852dda10d098f2f8daa2ee9081291329fd Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Apr 2013 21:08:21 -0700 Subject: [PATCH 0231/1537] Better handle material texture layers --- components/nifogre/ogrenifloader.cpp | 110 ++++++++++++++++----------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 5aa5ff80cb..b3ab4c0160 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -538,16 +538,51 @@ static std::map MaterialMap; static void warn(const std::string &msg) { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; } static void fail(const std::string &msg) { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; abort(); } +static std::string findTextureName(const std::string &filename) +{ + /* Bethesda at some point converted all their BSA + * textures from tga to dds for increased load speed, but all + * texture file name references were kept as .tga. + */ + static const char path[] = "textures\\"; + + std::string texname = filename; + Misc::StringUtils::toLower(texname); + + if(texname.compare(0, sizeof(path)-1, path) != 0) + texname = path + texname; + + Ogre::String::size_type pos = texname.rfind('.'); + if(pos != Ogre::String::npos && texname.compare(pos, texname.length() - pos, ".dds") != 0) + { + // since we know all (GOTY edition or less) textures end + // in .dds, we change the extension + texname.replace(pos, texname.length(), ".dds"); + + // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) + // verify, and revert if false (this call succeeds quickly, but fails slowly) + if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texname)) + { + texname = filename; + Misc::StringUtils::toLower(texname); + if(texname.compare(0, sizeof(path)-1, path) != 0) + texname = path + texname; + } + } + + return texname; +} + public: static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, @@ -575,47 +610,29 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int depthFlags = 3; // Default should be 1, but Bloodmoon's models are broken int specFlags = 0; - Ogre::String texName; + Ogre::String texName[7]; bool vertexColour = (shape->data->colors.size() != 0); // Texture - if(texprop && texprop->textures[0].inUse) + if(texprop) { - const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); - if(st->external) + for(int i = 0;i < 7;i++) { - /* Bethesda at some point converted all their BSA - * textures from tga to dds for increased load speed, but all - * texture file name references were kept as .tga. - */ - static const char path[] = "textures\\"; - - texName = st->filename; - Misc::StringUtils::toLower(texName); - - if(texName.compare(0, sizeof(path)-1, path) != 0) - texName = path + texName; - - Ogre::String::size_type pos = texName.rfind('.'); - if(pos != Ogre::String::npos && texName.compare(pos, texName.length() - pos, ".dds") != 0) + if(!texprop->textures[i].inUse) + continue; + if(texprop->textures[i].texture.empty()) { - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - texName.replace(pos, texName.length(), ".dds"); - - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texName)) - { - texName = st->filename; - Misc::StringUtils::toLower(texName); - if(texName.compare(0, sizeof(path)-1, path) != 0) - texName = path + texName; - } + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name+"\n"); + continue; } + + const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + if(st->external) + texName[i] = findTextureName(st->filename); + else + warn("Found internal texture, ignoring."); } - else warn("Found internal texture, ignoring."); } // Alpha modifiers @@ -655,8 +672,6 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String alpha = matprop->data.alpha; } - Ogre::String matname = name; - if(matprop || !texName.empty()) { // Generate a hash out of all properties that can affect the material. size_t h = 0; @@ -672,7 +687,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String boost::hash_combine(h, emissive.x); boost::hash_combine(h, emissive.y); boost::hash_combine(h, emissive.z); - boost::hash_combine(h, texName); + for(int i = 0;i < 7;i++) + { + if(!texName[i].empty()) + boost::hash_combine(h, texName[i]); + } boost::hash_combine(h, vertexColour); boost::hash_combine(h, alphaFlags); boost::hash_combine(h, alphaTest); @@ -687,11 +706,11 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String return itr->second; } // not found, create a new one - MaterialMap.insert(std::make_pair(h, matname)); + MaterialMap.insert(std::make_pair(h, name)); } // No existing material like this. Create a new one. - sh::MaterialInstance* instance = sh::Factory::getInstance ().createMaterialInstance (matname, "openmw_objects_base"); + sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); if(vertMode == 0 || !vertexColour) { instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); @@ -722,13 +741,18 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } - instance->setProperty("diffuseMap", sh::makeProperty(texName)); + instance->setProperty("diffuseMap", sh::makeProperty(texName[0])); + for(int i = 1;i < 7;i++) + { + if(!texName[i].empty()) + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); + } if (vertexColour) instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); // Add transparency if NiAlphaProperty was present - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName); + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); if (result.first) { alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ @@ -763,8 +787,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); // depth_func??? - sh::Factory::getInstance()._ensureMaterial(matname, "Default"); - return matname; + sh::Factory::getInstance()._ensureMaterial(name, "Default"); + return name; } }; From 512534be11a670c0102299bad95fa61264d3e604 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 2 Apr 2013 22:58:07 -0700 Subject: [PATCH 0232/1537] Read the correct texture resource for other layers --- components/nifogre/ogrenifloader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index b3ab4c0160..d1ce7ae318 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -627,7 +627,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String continue; } - const Nif::NiSourceTexture *st = texprop->textures[0].texture.getPtr(); + const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); if(st->external) texName[i] = findTextureName(st->filename); else From aac2ba1d5fff2e3b4ebfe22125343ac7aa027b62 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 12:24:13 +0200 Subject: [PATCH 0233/1537] Fix loading screen looking for wallpapers in a fixed group. --- apps/openmw/mwgui/loadingscreen.cpp | 20 +++++++++++++------- apps/openmw/mwgui/loadingscreen.hpp | 2 +- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index e7c7acb533..86f196d9f5 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -217,15 +217,21 @@ namespace MWGui void LoadingScreen::changeWallpaper () { - if (mResources.isNull ()) - mResources = Ogre::ResourceGroupManager::getSingleton ().findResourceNames ("General", "Splash_*.tga"); - - - if (mResources->size()) + if (mResources.empty()) { - std::string const & randomSplash = mResources->at (rand() % mResources->size()); + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = Ogre::ResourceGroupManager::getSingleton ().findResourceNames (*it, "Splash_*.tga"); + mResources.insert(mResources.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + } + } - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); + if (!mResources.empty()) + { + std::string const & randomSplash = mResources.at (rand() % mResources.size()); + + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME); mBackgroundImage->setImageTexture (randomSplash); } diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 24b3850710..176fc0f5d5 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -44,7 +44,7 @@ namespace MWGui Ogre::Rectangle2D* mRectangle; Ogre::MaterialPtr mBackgroundMaterial; - Ogre::StringVectorPtr mResources; + Ogre::StringVector mResources; bool mLoadingOn; From 095daca058e980471af9391b027e0f83f28c494b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 03:26:21 -0700 Subject: [PATCH 0234/1537] Create entities when iterating through the NIF --- components/nifogre/ogrenifloader.cpp | 185 ++++++++++++--------------- components/nifogre/ogrenifloader.hpp | 14 -- 2 files changed, 79 insertions(+), 120 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d1ce7ae318..89f55fbd4e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1088,9 +1088,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader typedef std::map LoaderMap; static LoaderMap sLoaders; -public: - NIFMeshLoader() - { } + NIFMeshLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1113,25 +1111,25 @@ public: findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); } - void createMeshes(const Nif::Node *node, MeshInfoList &meshes, int flags=0) + void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) { // Do not create meshes for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) return; - flags |= node->flags; - // Marker objects: just skip the entire node /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) return; + flags |= node->flags; + Nif::ExtraPtr e = node->extra; while(!e.empty()) { - Nif::NiStringExtraData *sd; - if((sd=dynamic_cast(e.getPtr())) != NULL) + if(e->recType == Nif::RC_NiStringExtraData) { + const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information // affecting the entire subtree of this obj if(sd->string == "MRK") @@ -1146,7 +1144,7 @@ public: if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { - const Nif::NiTriShape *shape = dynamic_cast(node); + const Nif::NiTriShape *shape = static_cast(node); Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); @@ -1165,7 +1163,15 @@ public: mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), shape->name)); + entities.mEntities.push_back(sceneMgr->createEntity(mesh)); + if(entities.mSkelBase) + { + Ogre::Entity *entity = entities.mEntities.back(); + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(entities.mSkelBase); + else + entities.mSkelBase->attachObjectToBone(shape->name, entity); + } } const Nif::NiNode *ninode = dynamic_cast(node); @@ -1175,12 +1181,12 @@ public: for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createMeshes(children[i].getPtr(), meshes, flags); + createEntities(sceneMgr, children[i].getPtr(), entities, flags); } } } - void createEmptyMesh(const Nif::Node *node, MeshInfoList &meshes) + void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all @@ -1199,91 +1205,61 @@ public: mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - meshes.push_back(MeshInfo(mesh->getName(), node->name)); + entities.mSkelBase = sceneMgr->createEntity(mesh); + entities.mEntities.push_back(entities.mSkelBase); + } + +public: + NIFMeshLoader() : mShapeIndex(~(size_t)0) + { } + + static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) + { + Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); + Nif::NIFFile &nif = *pnif.get(); + if(nif.numRecords() < 1) + { + nif.warn("Found no NIF records in "+name+"."); + return; + } + + // The first record is assumed to be the root node + const Nif::Record *r = nif.getRecord(0); + assert(r != NULL); + + const Nif::Node *node = dynamic_cast(r); + if(node == NULL) + { + nif.warn("First record in "+name+" was not a node, but a "+ + r->recName+"."); + return; + } + + bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); + if(!hasSkel) + hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); + + NIFMeshLoader meshldr(name, group); + if(hasSkel) + meshldr.createSkelBase(sceneMgr, node, entities); + meshldr.createEntities(sceneMgr, node, entities); } }; NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; -typedef std::map MeshInfoMap; -static MeshInfoMap sMeshInfoMap; - -MeshInfoList Loader::load(const std::string &name, const std::string &group) -{ - MeshInfoMap::const_iterator meshiter = sMeshInfoMap.find(name); - if(meshiter != sMeshInfoMap.end()) - return meshiter->second; - - MeshInfoList &meshes = sMeshInfoMap[name]; - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) - { - nif.warn("Found no NIF records in "+name+"."); - return meshes; - } - - // The first record is assumed to be the root node - Nif::Record const *r = nif.getRecord(0); - assert(r != NULL); - - Nif::Node const *node = dynamic_cast(r); - if(node == NULL) - { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return meshes; - } - - bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); - if(!hasSkel) - hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - - NIFMeshLoader meshldr(name, group); - if(hasSkel) - meshldr.createEmptyMesh(node, meshes); - meshldr.createMeshes(node, meshes, 0); - - return meshes; -} - EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, group); - if(meshes.size() == 0) - return entitylist; + NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); - Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - for(size_t i = 0;i < meshes.size();i++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - entitylist.mEntities.push_back(sceneMgr->createEntity(meshes[i].mMeshName)); - Ogre::Entity *entity = entitylist.mEntities.back(); - if(!entitylist.mSkelBase && entity->hasSkeleton()) - entitylist.mSkelBase = entity; - } - - if(entitylist.mSkelBase) - { - parentNode->attachObject(entitylist.mSkelBase); - for(size_t i = 0;i < entitylist.mEntities.size();i++) - { - Ogre::Entity *entity = entitylist.mEntities[i]; - if(entity != entitylist.mSkelBase && entity->hasSkeleton()) - { - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - parentNode->attachObject(entity); - } - else if(entity != entitylist.mSkelBase) - entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); - } - } - else - { - for(size_t i = 0;i < entitylist.mEntities.size();i++) - parentNode->attachObject(entitylist.mEntities[i]); + Ogre::Entity *entity = entitylist.mEntities[i]; + if(!entity->isAttached()) + parentNode->attachObject(entity); } return entitylist; @@ -1296,25 +1272,17 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - MeshInfoList meshes = load(name, group); - if(meshes.size() == 0) - return entitylist; + NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); bool isskinned = false; - Ogre::SceneManager *sceneMgr = parentNode->getCreator(); - std::string filter = "@shape=tri "+bonename; - Misc::StringUtils::toLower(filter); - for(size_t i = 0;i < meshes.size();i++) + for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Ogre::Entity *ent = sceneMgr->createEntity(meshes[i].mMeshName); - if(!entitylist.mSkelBase) + Ogre::Entity *ent = entitylist.mEntities[i]; + if(entitylist.mSkelBase != ent && ent->hasSkeleton()) { - if(ent->hasSkeleton()) - entitylist.mSkelBase = ent; - } - else if(!isskinned && ent->hasSkeleton()) isskinned = true; - entitylist.mEntities.push_back(ent); + break; + } } Ogre::Vector3 scale(1.0f); @@ -1323,20 +1291,21 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen if(isskinned) { + std::string filter = "@shape=tri "+bonename; + Misc::StringUtils::toLower(filter); for(size_t i = 0;i < entitylist.mEntities.size();i++) { Ogre::Entity *entity = entitylist.mEntities[i]; if(entity->hasSkeleton()) { - if(entity != entitylist.mSkelBase) - entity->shareSkeletonInstanceWith(entitylist.mSkelBase); - if(entity->getMesh()->getName().find(filter) != std::string::npos) + if(entity == entitylist.mSkelBase || + entity->getMesh()->getName().find(filter) != std::string::npos) parentNode->attachObject(entity); } else { - if(entity->getMesh()->getName().find(filter) != std::string::npos) - entitylist.mSkelBase->attachObjectToBone(meshes[i].mTargetNode, entity); + if(entity->getMesh()->getName().find(filter) == std::string::npos) + entity->detachFromParent(); } } } @@ -1344,8 +1313,12 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen { for(size_t i = 0;i < entitylist.mEntities.size();i++) { - Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entitylist.mEntities[i]); - tag->setScale(scale); + Ogre::Entity *entity = entitylist.mEntities[i]; + if(!entity->isAttached()) + { + Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); + tag->setScale(scale); + } } } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b8b2e3c007..92b153468a 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -48,22 +48,8 @@ struct EntityList { }; -/* This holds a list of mesh names, the names of their parent nodes, and the offset - * from their parent nodes. */ -struct MeshInfo { - std::string mMeshName; - std::string mTargetNode; - - MeshInfo(const std::string &name, const std::string &target) - : mMeshName(name), mTargetNode(target) - { } -}; -typedef std::vector MeshInfoList; - class Loader { - static MeshInfoList load(const std::string &name, const std::string &group); - public: static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, Ogre::SceneNode *parentNode, From f0d49fdbd06f99a297bb39c80b0b14317aade26e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 12:28:57 +0200 Subject: [PATCH 0235/1537] Create separate groups for each data dir / BSA file. --- apps/openmw/engine.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 948a06d471..17610e479f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -154,26 +154,36 @@ OMW::Engine::~Engine() void OMW::Engine::loadBSA() { + // We use separate resource groups to handle location priority. const Files::PathContainer& dataDirs = mFileCollections.getPaths(); - std::string dataDirectory; + + int i=0; for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { - dataDirectory = iter->string(); + // Last data dir has the highest priority + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i); + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + + std::string dataDirectory = iter->string(); std::cout << "Data dir " << dataDirectory << std::endl; - Bsa::addDir(dataDirectory, mFSStrict); + Bsa::addDir(dataDirectory, mFSStrict, groupName); + ++i; } - // BSA resources are put into a separate group. We want loose files to have priority over BSA resources, and this seems - // to be the only way to get Ogre to do just that. - Ogre::ResourceGroupManager::getSingleton ().createResourceGroup ("GroupBSA"); - + i=0; for (std::vector::const_iterator archive = mArchives.begin(); archive != mArchives.end(); ++archive) { if (mFileCollections.doesExist(*archive)) { + // Last BSA has the highest priority + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i); + + Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); + const std::string archivePath = mFileCollections.getPath(*archive).string(); std::cout << "Adding BSA archive " << archivePath << std::endl; - Bsa::addBSA(archivePath, "GroupBSA"); + Bsa::addBSA(archivePath, groupName); + ++i; } else { From 5625d73d84488a2c4eb2ff51270329a972733285 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 17:16:34 +0200 Subject: [PATCH 0236/1537] Bump texture support --- components/nif/property.hpp | 11 ++ components/nifogre/ogrenifloader.cpp | 26 ++++- extern/shiny/Docs/Macros.dox | 23 ++++- extern/shiny/Main/MaterialInstance.hpp | 1 + extern/shiny/Main/ShaderInstance.cpp | 15 +-- extern/shiny/Main/ShaderSet.cpp | 16 +++ extern/shiny/Main/ShaderSet.hpp | 4 + files/materials/objects.mat | 7 ++ files/materials/objects.shader | 134 +++++++++++++++++++++++-- 9 files changed, 211 insertions(+), 26 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index cd1e0a5d11..00cdc0e008 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -109,6 +109,17 @@ public: * 5 - Bump map texture * 6 - Decal texture */ + enum TextureType + { + BaseTexture = 0, + DarkTexture = 1, + DetailTexture = 2, + GlossTexture = 3, + GlowTexture = 4, + BumpTexture = 5, + DecalTexture = 6 + }; + Texture textures[7]; void read(NIFStream *nif) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 89f55fbd4e..c5dc7fbb98 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -555,11 +555,14 @@ static std::string findTextureName(const std::string &filename) * texture file name references were kept as .tga. */ static const char path[] = "textures\\"; + static const char path2[] = "textures/"; + std::string texname = filename; Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0) + if(texname.compare(0, sizeof(path)-1, path) != 0 + && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; Ogre::String::size_type pos = texname.rfind('.'); @@ -575,7 +578,8 @@ static std::string findTextureName(const std::string &filename) { texname = filename; Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0) + if(texname.compare(0, sizeof(path)-1, path) != 0 + && texname.compare(0, sizeof(path2)-1, path2) != 0) texname = path + texname; } } @@ -590,7 +594,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String const Nif::NiAlphaProperty *alphaprop, const Nif::NiVertexColorProperty *vertprop, const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + const Nif::NiSpecularProperty *specprop, + bool &needTangents) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); Ogre::MaterialPtr material = matMgr.getByName(name); @@ -634,6 +639,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String warn("Found internal texture, ignoring."); } } + needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); // Alpha modifiers if(alphaprop) @@ -741,7 +747,8 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } - instance->setProperty("diffuseMap", sh::makeProperty(texName[0])); + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); for(int i = 1;i < 7;i++) { if(!texName[i].empty()) @@ -1022,11 +1029,20 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } + bool needTangents=false; std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, texprop, matprop, alphaprop, - vertprop, zprop, specprop); + vertprop, zprop, specprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); + + // build tangents if the material needs them + if (needTangents) + { + unsigned short src,dest; + if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) + mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); + } } bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, diff --git a/extern/shiny/Docs/Macros.dox b/extern/shiny/Docs/Macros.dox index 0578c447f3..c04ebd3747 100644 --- a/extern/shiny/Docs/Macros.dox +++ b/extern/shiny/Docs/Macros.dox @@ -107,6 +107,23 @@ \section properties Property retrieval / binding + \subsection shPropertyHasValue shPropertyHasValue + + Usage: \@shPropertyHasValue(property) + + Gets replaced by 1 if the property's value is not empty, or 0 if it is empty. + Useful for checking whether an optional texture is present or not. + + Example: + \code + #if @shPropertyHasValue(specularMap) + // specular mapping code + #endif + #if @shPropertyHasValue(normalMap) + // normal mapping code + #endif + \endcode + \subsection shUniformProperty shUniformProperty Usage: \@shUniformProperty<4f|3f|2f|1f|int> (uniformName, property) @@ -130,15 +147,11 @@ Example: \code - #if @shPropertyBool(has_normal_map) + #if @shPropertyBool(has_vertex_colors) ... #endif \endcode - \subsection shPropertyNotBool shPropertyNotBool - - Same as shPropertyBool, but inverts the result (i.e. when shPropertyBool would return 0, this returns 1 and vice versa) - \subsection shPropertyString shPropertyString Retrieve a string property of the pass that this shader belongs to diff --git a/extern/shiny/Main/MaterialInstance.hpp b/extern/shiny/Main/MaterialInstance.hpp index 000f9d60c9..36ba37ddba 100644 --- a/extern/shiny/Main/MaterialInstance.hpp +++ b/extern/shiny/Main/MaterialInstance.hpp @@ -25,6 +25,7 @@ namespace sh public: virtual void requestedConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called before creating virtual void createdConfiguration (MaterialInstance* m, const std::string& configuration) = 0; ///< called after creating + virtual ~MaterialInstanceListener(){} }; /** diff --git a/extern/shiny/Main/ShaderInstance.cpp b/extern/shiny/Main/ShaderInstance.cpp index 1539128aba..b44c63c322 100644 --- a/extern/shiny/Main/ShaderInstance.cpp +++ b/extern/shiny/Main/ShaderInstance.cpp @@ -194,13 +194,6 @@ namespace sh bool val = retrieveValue(value, properties->getContext()).get(); replaceValue = val ? "1" : "0"; } - else if (cmd == "shPropertyNotBool") // same as above, but inverts the result - { - std::string propertyName = args[0]; - PropertyValuePtr value = properties->getProperty(propertyName); - bool val = retrieveValue(value, properties->getContext()).get(); - replaceValue = val ? "0" : "1"; - } else if (cmd == "shPropertyString") { std::string propertyName = args[0]; @@ -214,6 +207,14 @@ namespace sh std::string value = retrieveValue(properties->getProperty(propertyName), properties->getContext()).get(); replaceValue = (value == comparedAgainst) ? "1" : "0"; } + else if (isCmd(source, pos, "@shPropertyHasValue")) + { + assert(args.size() == 1); + std::string propertyName = args[0]; + PropertyValuePtr value = properties->getProperty(propertyName); + std::string val = retrieveValue(value, properties->getContext()).get(); + replaceValue = (val.empty() ? "0" : "1"); + } else throw std::runtime_error ("unknown command \"" + cmd + "\""); source.replace(pos, (end+1)-pos, replaceValue); diff --git a/extern/shiny/Main/ShaderSet.cpp b/extern/shiny/Main/ShaderSet.cpp index 413d7d1a26..628e0acee7 100644 --- a/extern/shiny/Main/ShaderSet.cpp +++ b/extern/shiny/Main/ShaderSet.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Factory.hpp" @@ -26,6 +27,10 @@ namespace sh std::ifstream stream(sourceFile.c_str(), std::ifstream::in); std::stringstream buffer; + boost::filesystem::path p (sourceFile); + p = p.branch_path(); + mBasePath = p.string(); + buffer << stream.rdbuf(); stream.close(); mSource = buffer.str(); @@ -52,6 +57,12 @@ namespace sh size_t start = currentToken.find('(')+1; mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); } + else if (boost::starts_with(currentToken, "@shPropertyHasValue")) + { + assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); + size_t start = currentToken.find('(')+1; + mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start)); + } else if (boost::starts_with(currentToken, "@shPropertyEqual")) { assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) @@ -135,6 +146,11 @@ namespace sh { boost::hash_combine(seed, retrieveValue(currentGlobalSettings->getProperty(*it), NULL).get()); } + for (std::vector::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it) + { + std::string v = retrieveValue(properties->getProperty(*it), properties->getContext()).get(); + boost::hash_combine(seed, static_cast(v != "")); + } boost::hash_combine(seed, static_cast(Factory::getInstance().getCurrentLanguage())); return seed; } diff --git a/extern/shiny/Main/ShaderSet.hpp b/extern/shiny/Main/ShaderSet.hpp index a423b6779f..b21278ac99 100644 --- a/extern/shiny/Main/ShaderSet.hpp +++ b/extern/shiny/Main/ShaderSet.hpp @@ -53,6 +53,10 @@ namespace sh std::vector mGlobalSettings; ///< names of the global settings that affect the shader source std::vector mProperties; ///< names of the per-material properties that affect the shader source + std::vector mPropertiesToExist; + ///< same as mProperties, however in this case, it is only relevant if the property is empty or not + /// (we don't care about the value) + ShaderInstanceMap mInstances; ///< maps permutation ID (generated from the properties) to \a ShaderInstance void parse(); ///< find out which properties and global settings affect the shader source diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 5e18a666a7..00b43a9d0d 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -6,6 +6,7 @@ material openmw_objects_base emissive 0.0 0.0 0.0 vertmode 0 diffuseMap black.png + normalMap is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default @@ -22,6 +23,7 @@ material openmw_objects_base { vertexcolor_mode $vertmode is_transparent $is_transparent + normalMap $normalMap } diffuse $diffuse @@ -38,6 +40,11 @@ material openmw_objects_base direct_texture $diffuseMap create_in_ffp true } + + texture_unit normalMap + { + direct_texture $normalMap + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index c8616e9d1e..73968a6b3e 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -14,13 +14,15 @@ #define NEED_DEPTH #endif +#define NORMAL_MAP @shPropertyHasValue(normalMap) + +// if normal mapping is enabled, we force pixel lighting +#define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) #define UNDERWATER @shGlobalSettingBool(render_refraction) #define VERTEXCOLOR_MODE @shPropertyString(vertexcolor_mode) -#define VERTEX_LIGHTING 1 - #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) #ifdef SH_VERTEX_SHADER @@ -42,6 +44,16 @@ shVertexInput(float2, uv0) shOutput(float2, UV) shNormalInput(float4) + +#if NORMAL_MAP + shTangentInput(float4) + shOutput(float3, tangentPassthrough) +#endif + +#if !VERTEX_LIGHTING + shOutput(float3, normalPassthrough) +#endif + #ifdef NEED_DEPTH shOutput(float, depthPassthrough) #endif @@ -52,6 +64,10 @@ shColourInput(float4) #endif +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + shOutput(float4, colourPassthrough) +#endif + #if VERTEX_LIGHTING shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) @@ -94,6 +110,15 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); UV = uv0; +#if NORMAL_MAP + tangentPassthrough = tangent.xyz; +#endif +#if !VERTEX_LIGHTING + normalPassthrough = normal.xyz; +#endif +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + colourPassthrough = colour; +#endif #ifdef NEED_DEPTH @@ -188,15 +213,31 @@ #endif SH_BEGIN_PROGRAM - shSampler2D(diffuseMap) - shInput(float2, UV) + shSampler2D(diffuseMap) + +#if NORMAL_MAP + shSampler2D(normalMap) +#endif + + shInput(float2, UV) + +#if NORMAL_MAP + shInput(float3, tangentPassthrough) +#endif +#if !VERTEX_LIGHTING + shInput(float3, normalPassthrough) +#endif #ifdef NEED_DEPTH shInput(float, depthPassthrough) #endif shInput(float3, objSpacePositionPassthrough) - + +#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING + shInput(float4, colourPassthrough) +#endif + #if FOG shUniform(float3, fogColour) @shAutoConstant(fogColour, fog_colour) shUniform(float4, fogParams) @shAutoConstant(fogParams, fog_params) @@ -222,23 +263,98 @@ #if (UNDERWATER) || (FOG) shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) - shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) + shUniform(float4, cameraPos) @shAutoConstant(cameraPos, camera_position) #endif #if UNDERWATER - shUniform(float, waterLevel) @shSharedParameter(waterLevel) + shUniform(float, waterLevel) @shSharedParameter(waterLevel) shUniform(float, waterEnabled) @shSharedParameter(waterEnabled) #endif #if VERTEX_LIGHTING shInput(float4, lightResult) shInput(float3, directionalResult) +#else + shUniform(float, lightCount) @shAutoConstant(lightCount, light_count) + shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights)) + shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour) + shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix) + #if VERTEXCOLOR_MODE != 2 + shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour) + #endif + #if VERTEXCOLOR_MODE != 2 + shUniform(float4, materialDiffuse) @shAutoConstant(materialDiffuse, surface_diffuse_colour) + #endif + #if VERTEXCOLOR_MODE != 1 + shUniform(float4, materialEmissive) @shAutoConstant(materialEmissive, surface_emissive_colour) + #endif #endif SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); - + +#if NORMAL_MAP + float3 normal = normalPassthrough; + float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); + float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz); + + #if SH_GLSL + tbn = transpose(tbn); + #endif + + float3 TSnormal = shSample(normalMap, UV.xy).xyz * 2 - 1; + + normal = normalize (shMatrixMult( transpose(tbn), TSnormal )); +#endif + +#if !VERTEX_LIGHTING + float3 viewPos = shMatrixMult(worldView, float4(objSpacePositionPassthrough,1)).xyz; + float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz); + + float3 lightDir; + float d; + float4 lightResult = float4(0,0,0,1); + @shForeach(@shGlobalSettingString(num_lights)) + lightDir = lightPosition[@shIterator].xyz - (viewPos * lightPosition[@shIterator].w); + d = length(lightDir); + lightDir = normalize(lightDir); + +#if VERTEXCOLOR_MODE == 2 + lightResult.xyz += colourPassthrough.xyz * lightDiffuse[@shIterator].xyz + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(viewNormal.xyz, lightDir), 0); +#else + lightResult.xyz += materialDiffuse.xyz * lightDiffuse[@shIterator].xyz + * shSaturate(1.0 / ((lightAttenuation[@shIterator].y) + (lightAttenuation[@shIterator].z * d) + (lightAttenuation[@shIterator].w * d * d))) + * max(dot(viewNormal.xyz, lightDir), 0); +#endif + +#if @shIterator == 0 + float3 directionalResult = lightResult.xyz; +#endif + + @shEndForeach + + +#if VERTEXCOLOR_MODE == 2 + lightResult.xyz += lightAmbient.xyz * colourPassthrough.xyz + materialEmissive.xyz; + lightResult.a *= colourPassthrough.a; +#endif +#if VERTEXCOLOR_MODE == 1 + lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + colourPassthrough.xyz; +#endif +#if VERTEXCOLOR_MODE == 0 + lightResult.xyz += lightAmbient.xyz * materialAmbient.xyz + materialEmissive.xyz; +#endif + +#if VERTEXCOLOR_MODE != 2 + lightResult.a *= materialDiffuse.a; +#endif +#endif + // shadows only for the first (directional) light #if SHADOWS float shadow = depthShadowPCF (shadowMap0, lightSpacePos0, invShadowmapSize0); @@ -275,7 +391,7 @@ #if FOG float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w); - + #if UNDERWATER shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, UNDERWATER_COLOUR, shSaturate(length(waterEyePos-worldPos) / VISIBILITY)); From ae3e4ecf8b7598a021970ab2c3f1a75650822781 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:02:30 +0200 Subject: [PATCH 0237/1537] Finished enchanting --- apps/openmw/mwgui/enchantingdialog.cpp | 20 ++++++++++++++++++-- apps/openmw/mwgui/enchantingdialog.hpp | 1 + apps/openmw/mwmechanics/enchanting.cpp | 3 ++- files/mygui/openmw_enchanting_dialog.layout | 4 ++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 1ed80127d4..23e400c367 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -32,6 +32,7 @@ namespace MWGui getWidget(mTypeButton, "TypeButton"); getWidget(mBuyButton, "BuyButton"); getWidget(mPrice, "PriceLabel"); + getWidget(mPriceText, "PriceTextLabel"); setWidgets(mAvailableEffectsList, mUsedEffectsView); @@ -94,19 +95,34 @@ namespace MWGui mPtr = actor; startEditing (); + + mPrice->setVisible(true); } void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWWorld::Ptr gem = soulgem; mEnchanting.setSelfEnchanting(true); mEnchanting.setEnchanter(player); mPtr = player; startEditing(); - mEnchanting.setSoulGem(gem); + mEnchanting.setSoulGem(soulgem); + + MyGUI::ImageBox* image = mSoulBox->createWidget("ImageBox", MyGUI::IntCoord(0, 0, 32, 32), MyGUI::Align::Default); + std::string path = std::string("icons\\"); + path += MWWorld::Class::get(soulgem).getInventoryIcon(soulgem); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture (path); + image->setUserString ("ToolTipType", "ItemPtr"); + image->setUserData(soulgem); + image->eventMouseButtonClick += MyGUI::newDelegate(this, &EnchantingDialog::onRemoveSoul); + + mPrice->setVisible(false); + mPriceText->setVisible(false); } void EnchantingDialog::onReferenceUnavailable () diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 347b37e908..a7861c422d 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -56,6 +56,7 @@ namespace MWGui MyGUI::TextBox* mCastCost; MyGUI::TextBox* mCharge; MyGUI::TextBox* mPrice; + MyGUI::TextBox* mPriceText; MWMechanics::Enchanting mEnchanting; ESM::EffectList mEffectList; diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 45db667d26..884c4d8963 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -88,7 +88,8 @@ namespace MWMechanics MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); - payForEnchantment(); + if(!mSelfEnchanting) + payForEnchantment(); return true; } diff --git a/files/mygui/openmw_enchanting_dialog.layout b/files/mygui/openmw_enchanting_dialog.layout index 41b8ffa938..f64d21deaa 100644 --- a/files/mygui/openmw_enchanting_dialog.layout +++ b/files/mygui/openmw_enchanting_dialog.layout @@ -97,11 +97,11 @@ - + - + From 21796197217e50a3cffe24f95008a46edd42da62 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:06:11 +0200 Subject: [PATCH 0238/1537] Small enchanting fix --- apps/openmw/mwgui/enchantingdialog.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 23e400c367..276e7a9047 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -95,8 +95,6 @@ namespace MWGui mPtr = actor; startEditing (); - - mPrice->setVisible(true); } void EnchantingDialog::startSelfEnchanting(MWWorld::Ptr soulgem) @@ -123,6 +121,7 @@ namespace MWGui mPrice->setVisible(false); mPriceText->setVisible(false); + updateLabels(); } void EnchantingDialog::onReferenceUnavailable () From 30654a1faa0d9181e4beb28babfd09fd801b809b Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:11:57 +0200 Subject: [PATCH 0239/1537] Added removing of ogre static. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d31e4afc8d..f517a4da83 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq + - sudo apt-get remove -qq libogre-static-dev - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: From 4bf87948a03e6073c2c527c25f7ee45d7ba47c18 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:19:46 +0200 Subject: [PATCH 0240/1537] Removed clang compilation target. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f517a4da83..4852efb810 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: cpp compiler: - - clang - gcc before_script: - mkdir build From 08e9bb0236447d7a952f13791180ba122a5fad4a Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 3 Apr 2013 18:25:40 +0200 Subject: [PATCH 0241/1537] Another small enchanting fix --- apps/openmw/mwmechanics/enchanting.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index 884c4d8963..d92acdafc0 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -7,6 +7,7 @@ #include "creaturestats.hpp" #include "npcstats.hpp" +#include namespace MWMechanics { @@ -56,7 +57,7 @@ namespace MWMechanics enchantment.mData.mCharge = getGemCharge(); //Exception for Azura Star, it's not destroyed after enchanting - if(mSoulGemPtr.get()->mBase->mId=="Misc_SoulGem_Azura") + if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) mSoulGemPtr.getCellRef().mSoul=""; else mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); From 71b4319a0ce170b9815c480ee5e5a1cb2b1f0d6f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 18:31:38 +0200 Subject: [PATCH 0242/1537] Yet another change in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4852efb810..a9c47aa4e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq ffmpeg libboost-all-dev libbullet-dev libogre-dev libmygui-static-dev libqt4-dev libgtest-dev google-mock zziplib-bin libmpg123-dev libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libboost-program-options-dev libboost-system-dev libboost-wave-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-dev libqt4-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: make branches: only: From a9b56eedc3c220a108915d3caf9234a60129c99e Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 18:51:40 +0200 Subject: [PATCH 0243/1537] Support NIF "glow maps", which are basically an emissive channel. --- components/nif/property.hpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 7 ++++++ files/materials/objects.mat | 14 ++++++++++++ files/materials/objects.shader | 33 ++++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 6 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index 00cdc0e008..fd96ad0481 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -64,7 +64,7 @@ public: bool inUse; NiSourceTexturePtr texture; - int clamp, set, filter; + int clamp, uvSet, filter; short unknown2; void read(NIFStream *nif) @@ -75,7 +75,7 @@ public: texture.read(nif); clamp = nif->getInt(); filter = nif->getInt(); - set = nif->getInt(); + uvSet = nif->getInt(); // I have no idea, but I think these are actually two // PS2-specific shorts (ps2L and ps2K), followed by an unknown diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5dc7fbb98..f8eca821ff 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -749,6 +749,13 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); + if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) + { + instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + } + for(int i = 1;i < 7;i++) { if(!texName[i].empty()) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 00b43a9d0d..8740c82c34 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -7,6 +7,9 @@ material openmw_objects_base vertmode 0 diffuseMap black.png normalMap + emissiveMap + use_emissive_map false + emissiveMapUVSet 0 is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default @@ -24,6 +27,8 @@ material openmw_objects_base vertexcolor_mode $vertmode is_transparent $is_transparent normalMap $normalMap + emissiveMapUVSet $emissiveMapUVSet + emissiveMap $emissiveMap } diffuse $diffuse @@ -39,12 +44,21 @@ material openmw_objects_base { direct_texture $diffuseMap create_in_ffp true + tex_coord_set $emissiveMapUVSet } texture_unit normalMap { direct_texture $normalMap } + + texture_unit emissiveMap + { + create_in_ffp $use_emissive_map + colour_op add + direct_texture $emissiveMap + tex_coord_set $emissiveMapUVSet + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 73968a6b3e..d0e8173733 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -15,6 +15,10 @@ #endif #define NORMAL_MAP @shPropertyHasValue(normalMap) +#define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) + +// right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more +#define SECOND_UV_SET @shPropertyString(emissiveMapUVSet) // if normal mapping is enabled, we force pixel lighting #define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) @@ -42,7 +46,11 @@ #endif shVertexInput(float2, uv0) - shOutput(float2, UV) +#if SECOND_UV_SET + shVertexInput(float2, uv1) +#endif + shOutput(float4, UV) + shNormalInput(float4) #if NORMAL_MAP @@ -109,7 +117,12 @@ SH_START_PROGRAM { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV = uv0; + + UV.xy = uv0; +#if SECOND_UV_SET + UV.zw = uv1; +#endif + #if NORMAL_MAP tangentPassthrough = tangent.xyz; #endif @@ -219,7 +232,11 @@ shSampler2D(normalMap) #endif - shInput(float2, UV) +#if EMISSIVE_MAP + shSampler2D(emissiveMap) +#endif + + shInput(float4, UV) #if NORMAL_MAP shInput(float3, tangentPassthrough) @@ -294,7 +311,7 @@ SH_START_PROGRAM { - shOutputColour(0) = shSample(diffuseMap, UV); + shOutputColour(0) = shSample(diffuseMap, UV.xy); #if NORMAL_MAP float3 normal = normalPassthrough; @@ -399,6 +416,14 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); #endif +#endif + +#if EMISSIVE_MAP + #if SECOND_UV_SET + shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz; + #else + shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz; + #endif #endif // prevent negative colour output (for example with negative lights) From 2a5fc7cd822e9a204b63bfdf858cec1c7eefba53 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:02:21 +0200 Subject: [PATCH 0244/1537] Change in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index a9c47aa4e2..4d1257d2bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-filesystem-dev libboost-thread-dev libboost-chrono-dev libboost-program-options-dev libboost-system-dev libboost-wave-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-dev libqt4-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev -script: make + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev 0ibpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev +script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: - master From f655b9997cc4e04f606f726452ad241eabe57c5c Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:10:57 +0200 Subject: [PATCH 0245/1537] Added printing CMakeCache.txt file For debug purposes, should be removed if compilation succeed. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4d1257d2bf..d99809590e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ before_script: - mkdir build - cd build - cmake .. -DMYGUI_STATIC=1 + - cat CMakeCache.txt before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps From d070860f0943c2fa5ac22762128554b5fcf623be Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:14:13 +0200 Subject: [PATCH 0246/1537] Fixed typo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d99809590e..7f361f5d40 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev 0ibpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: From af509ce016ee85094fcd75f69eadf29109c2757f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Wed, 3 Apr 2013 19:19:25 +0200 Subject: [PATCH 0247/1537] Restored building with static ogre. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7f361f5d40..db0a47d844 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DMYGUI_STATIC=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 - cat CMakeCache.txt before_install: - git submodule update --init --recursive From 8ca88d1a708b05741240eb1e1b04d63449f2f2ab Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 21:13:01 +0200 Subject: [PATCH 0248/1537] Fix merchant repair menu allowing repair of repair items --- apps/openmw/mwgui/merchantrepair.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 0a65326050..1c9056748b 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -40,7 +40,8 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::ContainerStore& store = MWWorld::Class::get(player).getContainerStore(player); - for (MWWorld::ContainerStoreIterator iter (store.begin()); + int categories = MWWorld::ContainerStore::Type_Weapon | MWWorld::ContainerStore::Type_Armor; + for (MWWorld::ContainerStoreIterator iter (store.begin(categories)); iter!=store.end(); ++iter) { if (MWWorld::Class::get(*iter).hasItemHealth(*iter)) From 43cdbd033d690dd904bf6f98dd39423f3182443f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 21:14:49 +0200 Subject: [PATCH 0249/1537] Display remaining item health / enchantment charge in HUD icons, display remaining enchanment charge in tooltips --- apps/openmw/mwbase/windowmanager.hpp | 4 ++-- apps/openmw/mwclass/armor.cpp | 2 ++ apps/openmw/mwclass/clothing.cpp | 2 ++ apps/openmw/mwclass/weapon.cpp | 3 +++ apps/openmw/mwgui/inventorywindow.cpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 4 ++-- apps/openmw/mwgui/tooltips.hpp | 2 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 9 +++++++-- apps/openmw/mwgui/windowmanagerimp.hpp | 4 ++-- 11 files changed, 25 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b271aed182..976d7d84c1 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -182,8 +182,8 @@ namespace MWBase virtual void activateQuickKey (int index) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; - virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) = 0; - virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) = 0; + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; + virtual void setSelectedWeapon(const MWWorld::Ptr& item) = 0; virtual void unsetSelectedSpell() = 0; virtual void unsetSelectedWeapon() = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index b94c270d56..320944d3ce 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -260,6 +260,8 @@ namespace MWClass } info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; info.text = text; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index d65376898e..abad267675 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -207,6 +207,8 @@ namespace MWClass } info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; info.text = text; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index ed2a095e37..0a527262f8 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -349,6 +349,9 @@ namespace MWClass info.enchant = ref->mBase->mEnchant; + if (!info.enchant.empty()) + info.remainingEnchantCharge = ptr.getCellRef().mEnchantmentCharge; + if (MWBase::Environment::get().getWindowManager()->getFullHelp()) { text += MWGui::ToolTips::getMiscString(ref->mRef.mOwner, "Owner"); text += MWGui::ToolTips::getMiscString(ref->mBase->mScript, "Script"); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index aeab5f94aa..001f42bd11 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -294,7 +294,7 @@ namespace MWGui if (weaponSlot == invStore.end()) mWindowManager.unsetSelectedWeapon(); else - mWindowManager.setSelectedWeapon(*weaponSlot, 100); /// \todo track weapon durability + mWindowManager.setSelectedWeapon(*weaponSlot); /// \todo track weapon durability mPreviewDirty = true; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 5ea13fb0d7..2e4bf9100b 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -346,7 +346,7 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % + mWindowManager.setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d7fb0e1bcd..021a849a08 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -382,7 +382,7 @@ namespace MWGui store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item, 100); /// \todo track charge % + mWindowManager.setSelectedEnchantItem(item); updateSpells(); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index af3e146bba..9292e60e5c 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -456,8 +456,8 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) if (enchant->mData.mType == ESM::Enchantment::WhenStrikes || enchant->mData.mType == ESM::Enchantment::WhenUsed) { - /// \todo store the current enchantment charge somewhere - int charge = enchant->mData.mCharge; + int maxCharge = enchant->mData.mCharge; + int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; const int chargeWidth = 204; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index ba94915cc7..da5a35221c 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -17,6 +17,7 @@ namespace MWGui : isPotion(false) , imageSize(32) , wordWrap(true) + , remainingEnchantCharge(-1) {} std::string caption; @@ -26,6 +27,7 @@ namespace MWGui // enchantment (for cloth, armor, weapons) std::string enchant; + int remainingEnchantCharge; // effects (for potions, ingredients) Widgets::SpellEffectList effects; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c975b2cdba..f994683a66 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -933,14 +933,19 @@ void WindowManager::setSelectedSpell(const std::string& spellId, int successChan mSpellWindow->setTitle(spell->mName); } -void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) +void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + .find(MWWorld::Class::get(item).getEnchantment(item)); + + int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; mHud->setSelectedEnchantItem(item, chargePercent); mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); } -void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) +void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) { + int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; mHud->setSelectedWeapon(item, durabilityPercent); mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index c14c6b2fe4..3c9fc586a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -179,8 +179,8 @@ namespace MWGui virtual void activateQuickKey (int index); virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); - virtual void setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent); - virtual void setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent); + virtual void setSelectedEnchantItem(const MWWorld::Ptr& item); + virtual void setSelectedWeapon(const MWWorld::Ptr& item); virtual void unsetSelectedSpell(); virtual void unsetSelectedWeapon(); From ebaf80d53921e51aa9b3c8cd823ef191b2490d9a Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 3 Apr 2013 23:55:57 +0200 Subject: [PATCH 0250/1537] Trace actors onto the ground after load, when moved to a different cell by the console or on player cell change. --- apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwclass/creature.cpp | 6 +++ apps/openmw/mwclass/creature.hpp | 2 + apps/openmw/mwclass/npc.cpp | 5 ++ apps/openmw/mwclass/npc.hpp | 2 + apps/openmw/mwrender/renderingmanager.cpp | 27 +++++----- apps/openmw/mwrender/renderingmanager.hpp | 2 + apps/openmw/mwrender/terrain.cpp | 11 ++++ apps/openmw/mwrender/terrain.hpp | 3 ++ .../mwscript/transformationextensions.cpp | 3 ++ apps/openmw/mwworld/class.cpp | 4 ++ apps/openmw/mwworld/class.hpp | 3 ++ apps/openmw/mwworld/physicssystem.cpp | 50 ++++++++++++++++++- apps/openmw/mwworld/physicssystem.hpp | 1 + apps/openmw/mwworld/scene.cpp | 6 ++- apps/openmw/mwworld/worldimp.cpp | 19 +++++++ apps/openmw/mwworld/worldimp.hpp | 3 ++ libs/openengine/bullet/physic.cpp | 3 +- 18 files changed, 138 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8eea383eb4..040dc703c0 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -216,6 +216,9 @@ namespace MWBase virtual MWWorld::Ptr getFacedObject() = 0; ///< Return pointer to the object the player is looking at, if it is within activation range + virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; + ///< Adjust position after load to be on ground. Must be called after model load. + virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 1097f8f29c..04889360f3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -9,6 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/ptr.hpp" #include "../mwworld/actiontalk.hpp" @@ -86,6 +87,11 @@ namespace MWClass return ref->mBase->mId; } + void Creature::adjustPosition(const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr); + } + void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { MWRender::Actors& actors = renderingInterface.getActors(); diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index ea356165eb..297c2ea61b 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -22,6 +22,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + 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 cd6b0def11..7cda87bb15 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -160,6 +160,11 @@ namespace MWClass return ref->mBase->mId; } + void Npc::adjustPosition(const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getWorld()->adjustPosition(ptr); + } + void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 1a10bce6c1..d1a9158fdf 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -44,6 +44,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + 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/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7c442c6868..2f49a40316 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -529,25 +529,28 @@ void RenderingManager::applyFog (bool underwater) void RenderingManager::setAmbientMode() { - switch (mAmbientMode) - { + switch (mAmbientMode) + { case 0: - - setAmbientColour(mAmbientColor); - break; + setAmbientColour(mAmbientColor); + break; case 1: - - setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); - break; + setAmbientColour(0.7f*mAmbientColor + 0.3f*ColourValue(1,1,1)); + break; case 2: - - setAmbientColour(ColourValue(1,1,1)); - break; - } + setAmbientColour(ColourValue(1,1,1)); + break; + } } +float RenderingManager::getTerrainHeightAt(Ogre::Vector3 worldPos) +{ + return mTerrainManager->getTerrainHeightAt(worldPos); +} + + void RenderingManager::configureAmbient(MWWorld::Ptr::CellStore &mCell) { mAmbientColor.setAsABGR (mCell.mCell->mAmbi.mAmbient); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index fd43438ca5..b343a60bdb 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -158,6 +158,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void getTriangleBatchCount(unsigned int &triangles, unsigned int &batches); + float getTerrainHeightAt (Ogre::Vector3 worldPos); + void setGlare(bool glare); void skyEnable (); void skyDisable (); diff --git a/apps/openmw/mwrender/terrain.cpp b/apps/openmw/mwrender/terrain.cpp index 438366873c..c27dce6cad 100644 --- a/apps/openmw/mwrender/terrain.cpp +++ b/apps/openmw/mwrender/terrain.cpp @@ -71,6 +71,17 @@ namespace MWRender //---------------------------------------------------------------------------------------------- + float TerrainManager::getTerrainHeightAt(Vector3 worldPos) + { + Ogre::Terrain* terrain = NULL; + float height = mTerrainGroup.getHeightAtWorldPosition(worldPos, &terrain); + if (terrain == NULL) + return std::numeric_limits().min(); + return height; + } + + //---------------------------------------------------------------------------------------------- + TerrainManager::~TerrainManager() { OGRE_DELETE mTerrainGlobals; diff --git a/apps/openmw/mwrender/terrain.hpp b/apps/openmw/mwrender/terrain.hpp index 484a0dbe3a..45c56390e8 100644 --- a/apps/openmw/mwrender/terrain.hpp +++ b/apps/openmw/mwrender/terrain.hpp @@ -40,6 +40,9 @@ namespace MWRender{ void cellAdded(MWWorld::CellStore* store); void cellRemoved(MWWorld::CellStore* store); + + float getTerrainHeightAt (Ogre::Vector3 worldPos); + private: Ogre::TerrainGlobalOptions* mTerrainGlobals; Ogre::TerrainGroup mTerrainGroup; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index d86a6e3486..000cc545db 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -303,6 +303,8 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + + MWBase::Environment::get().getWorld()->adjustPosition(ptr); } else { @@ -341,6 +343,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + MWBase::Environment::get().getWorld()->adjustPosition(ptr); } }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 98579797c7..2dfa241b3b 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,6 +259,10 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } + void Class::adjustPosition(const MWWorld::Ptr& ptr) const + { + } + MWWorld::Ptr Class::copyToCellImpl(const Ptr &ptr, CellStore &cell) const { diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e34ebdde77..de4741e38b 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -81,6 +81,9 @@ namespace MWWorld ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. + virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + ///< Adjust position to stand on ground. Must be called post model load + virtual MWMechanics::CreatureStats& getCreatureStats (const Ptr& ptr) const; ///< Return creature stats or throw an exception, if class does not have creature stats /// (default implementation: throw an exceoption) diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 28f3317065..19ee2e517b 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -88,6 +88,50 @@ namespace MWWorld } public: + static Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr, OEngine::Physic::PhysicEngine *engine) + { + const ESM::Position &refpos = ptr.getRefData().getPosition(); + Ogre::Vector3 position(refpos.pos); + + bool hit=false; + bool isInterior = !ptr.getCell()->isExterior(); + + OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); + if (!physicActor) + return position; + + bool wasCollisionMode = physicActor->getCollisionMode(); + + physicActor->enableCollisions(false); + + Ogre::Vector3 halfExtents = physicActor->getHalfExtents();// + Vector3(1,1,1); + + Ogre::Vector3 newPosition = position; + + traceResults trace; //no initialization needed + + int maxHeight = 400.f; + int steps = 100; + for (int i=0; isetOnGround(hit); + physicActor->enableCollisions(wasCollisionMode); + + if (hit) + return newPosition; + else + return position; + } + + static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { @@ -318,7 +362,7 @@ namespace MWWorld btVector3 btTo = btVector3(to.x, to.y, to.z); std::pair test = mEngine->rayTest(btFrom, btTo); - if (test.first == "") { + if (test.second == -1) { return std::make_pair(false, Ogre::Vector3()); } return std::make_pair(true, ray.getPoint(len * test.second)); @@ -351,6 +395,10 @@ namespace MWWorld return MovementSolver::move(ptr, movement, time, gravity, mEngine); } + Ogre::Vector3 PhysicsSystem::traceDown(const MWWorld::Ptr &ptr) + { + return MovementSolver::traceDown(ptr, mEngine); + } void PhysicsSystem::addHeightField (float* heights, int x, int y, float yoffset, diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 2e48be4079..4eec9367cb 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -51,6 +51,7 @@ namespace MWWorld bool toggleCollisionMode(); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); + Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); std::vector < std::pair > getFacedHandles (float queryDistance); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 339026ca60..c8853f4842 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -51,6 +51,7 @@ namespace class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); + class_.adjustPosition(ptr); } catch (const std::exception& e) { @@ -99,7 +100,6 @@ namespace MWWorld } mRendering.removeCell(*iter); - //mPhysics->removeObject("Unnamed_43"); MWBase::Environment::get().getWorld()->getLocalScripts().clearCell (*iter); MWBase::Environment::get().getMechanicsManager()->drop (*iter); @@ -165,6 +165,8 @@ namespace MWWorld float y = Ogre::Radian(pos.rot[1]).valueDegrees(); float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); + + world->adjustPosition(player); } MWBase::MechanicsManager *mechMgr = @@ -355,6 +357,8 @@ namespace MWWorld float y = Ogre::Radian(position.rot[1]).valueDegrees(); float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayer().getPlayer(), x, y, z); + + world->adjustPosition(world->getPlayer().getPlayer()); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae0e02c8c9..2ce753b816 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -709,6 +709,7 @@ namespace MWWorld pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; + Ogre::Vector3 vec(x, y, z); CellStore *currCell = ptr.getCell(); @@ -822,6 +823,24 @@ namespace MWWorld } } + void World::adjustPosition(const Ptr &ptr) + { + Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + + if (!isFlying(ptr)) + { + Ogre::Vector3 traced = mPhysics->traceDown(ptr); + if (traced.z < pos.z) + pos.z = traced.z; + } + + float terrainHeight = mRendering->getTerrainHeightAt(pos); + if (pos.z < terrainHeight) + pos.z = terrainHeight; + + moveObject(ptr, pos.x, pos.y, pos.z); + } + void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) { rotateObjectImp(ptr, Ogre::Vector3(Ogre::Degree(x).valueRadians(), diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 8cff50bd16..5ae87a1ff7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -188,6 +188,9 @@ namespace MWWorld virtual Ptr searchPtrViaHandle (const std::string& handle); ///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found + virtual void adjustPosition (const Ptr& ptr); + ///< Adjust position after load to be on ground. Must be called after model load. + virtual void enable (const Ptr& ptr); virtual void disable (const Ptr& ptr); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 7b831d32c5..f71fa4320b 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -323,7 +323,8 @@ namespace Physic mHeightFieldMap [name] = hf; - dynamicsWorld->addRigidBody(body,CollisionType_World,CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal); + dynamicsWorld->addRigidBody(body,CollisionType_World|CollisionType_Raycasting, + CollisionType_World|CollisionType_ActorInternal|CollisionType_ActorExternal|CollisionType_Raycasting); } void PhysicEngine::removeHeightField(int x, int y) From fea44c05d4a337ffe4f5543c94c2a9ec3ab724bc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:10:26 +0200 Subject: [PATCH 0251/1537] added class record verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/classcheck.cpp | 63 ++++++++++++++++++++++++++ apps/opencs/model/tools/classcheck.hpp | 29 ++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ apps/opencs/model/world/data.cpp | 10 ++++ apps/opencs/model/world/data.hpp | 4 ++ 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/classcheck.cpp create mode 100644 apps/opencs/model/tools/classcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index a305d90d93..adfc5f4aeb 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck + stage verifier mandatoryid skillcheck classcheck ) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp new file mode 100644 index 0000000000..302af6b9db --- /dev/null +++ b/apps/opencs/model/tools/classcheck.cpp @@ -0,0 +1,63 @@ + +#include "classcheck.hpp" + +#include +#include + +#include +#include + +#include "../world/universalid.hpp" + +CSMTools::ClassCheckStage::ClassCheckStage (const CSMWorld::IdCollection& classes) +: mClasses (classes) +{} + +int CSMTools::ClassCheckStage::setup() +{ + return mClasses.getSize(); +} + +void CSMTools::ClassCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Class& class_= mClasses.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Class, class_.mId); + + // test for empty name and description + if (class_.mName.empty()) + messages.push_back (id.toString() + "|" + class_.mId + " has an empty name"); + + if (class_.mDescription.empty()) + messages.push_back (id.toString() + "|" + class_.mId + " has an empty description"); + + // test for invalid attributes + for (int i=0; i<2; ++i) + if (class_.mData.mAttribute[i]==-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set"; + + messages.push_back (stream.str()); + } + + // test for non-unique skill + std::map skills; // ID, number of occurrences + + for (int i=0; i<5; ++i) + for (int i2=0; i2<2; ++i2) + ++skills[class_.mData.mSkills[i][i2]]; + + for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + if (iter->second>1) + { + std::ostringstream stream; + + stream + << id.toString() << "|" + << ESM::Skill::indexToId (iter->first) << " is listed more than once"; + + messages.push_back (stream.str()); + } +} \ No newline at end of file diff --git a/apps/opencs/model/tools/classcheck.hpp b/apps/opencs/model/tools/classcheck.hpp new file mode 100644 index 0000000000..a29d7c8b78 --- /dev/null +++ b/apps/opencs/model/tools/classcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_CLASSCHECK_H +#define CSM_TOOLS_CLASSCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that class records are internally consistent + class ClassCheckStage : public Stage + { + const CSMWorld::IdCollection& mClasses; + + public: + + ClassCheckStage (const CSMWorld::IdCollection& classes); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 33cc3cc61b..84a6910ecc 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -13,6 +13,7 @@ #include "reportmodel.hpp" #include "mandatoryid.hpp" #include "skillcheck.hpp" +#include "classcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -54,6 +55,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds)); mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); + + mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); } return mVerifier; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 13fff7f096..fc6cc01220 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -107,6 +107,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSkills() return mSkills; } +const CSMWorld::IdCollection& CSMWorld::Data::getClasses() const +{ + return mClasses; +} + +CSMWorld::IdCollection& CSMWorld::Data::getClasses() +{ + return mClasses; +} + const CSMWorld::IdCollection& CSMWorld::Data::getFactions() const { return mFactions; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 1e2894774a..16a9685a53 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -54,6 +54,10 @@ namespace CSMWorld IdCollection& getSkills(); + const IdCollection& getClasses() const; + + IdCollection& getClasses(); + const IdCollection& getFactions() const; IdCollection& getFactions(); From 06533b8d71a10139816996a3f68042b7f4aff14e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:31:10 +0200 Subject: [PATCH 0252/1537] additional check for using the same attribute twice in a class --- apps/opencs/model/tools/classcheck.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/opencs/model/tools/classcheck.cpp b/apps/opencs/model/tools/classcheck.cpp index 302af6b9db..da2e9f19a6 100644 --- a/apps/opencs/model/tools/classcheck.cpp +++ b/apps/opencs/model/tools/classcheck.cpp @@ -42,6 +42,15 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector& me messages.push_back (stream.str()); } + if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Class lists same attribute twice"; + + messages.push_back (stream.str()); + } + // test for non-unique skill std::map skills; // ID, number of occurrences From b5eaa464ad8cb840437a9280f278f25813e18930 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:39:43 +0200 Subject: [PATCH 0253/1537] added faction record verifier --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/factioncheck.cpp | 61 ++++++++++++++++++++++++ apps/opencs/model/tools/factioncheck.hpp | 29 +++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/factioncheck.cpp create mode 100644 apps/opencs/model/tools/factioncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index adfc5f4aeb..07766507f7 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck + stage verifier mandatoryid skillcheck classcheck factioncheck ) diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp new file mode 100644 index 0000000000..ea4a87eec8 --- /dev/null +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -0,0 +1,61 @@ + +#include "factioncheck.hpp" + +#include +#include + +#include +#include + +#include "../world/universalid.hpp" + +CSMTools::FactionCheckStage::FactionCheckStage (const CSMWorld::IdCollection& factions) +: mFactions (factions) +{} + +int CSMTools::FactionCheckStage::setup() +{ + return mFactions.getSize(); +} + +void CSMTools::FactionCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Faction& faction = mFactions.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Faction, faction.mId); + + // test for empty name + if (faction.mName.empty()) + messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); + + // test for invalid attributes + if (faction.mData.mAttributes[0]==faction.mData.mAttributes[1] && faction.mData.mAttributes[0]!=-1) + { + std::ostringstream stream; + + stream << id.toString() << "|Faction lists same attribute twice"; + + messages.push_back (stream.str()); + } + + // test for non-unique skill + std::map skills; // ID, number of occurrences + + for (int i=0; i<6; ++i) + if (faction.mData.mSkills[i]!=-1) + ++skills[faction.mData.mSkills[i]]; + + for (std::map::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) + if (iter->second>1) + { + std::ostringstream stream; + + stream + << id.toString() << "|" + << ESM::Skill::indexToId (iter->first) << " is listed more than once"; + + messages.push_back (stream.str()); + } + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/factioncheck.hpp b/apps/opencs/model/tools/factioncheck.hpp new file mode 100644 index 0000000000..8686505727 --- /dev/null +++ b/apps/opencs/model/tools/factioncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_FACTIONCHECK_H +#define CSM_TOOLS_FACTIONCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that faction records are internally consistent + class FactionCheckStage : public Stage + { + const CSMWorld::IdCollection& mFactions; + + public: + + FactionCheckStage (const CSMWorld::IdCollection& factions); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 84a6910ecc..db45de43e5 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -14,6 +14,7 @@ #include "mandatoryid.hpp" #include "skillcheck.hpp" #include "classcheck.hpp" +#include "factioncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -57,6 +58,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SkillCheckStage (mData.getSkills())); mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); + + mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); } return mVerifier; From 7136ac0079ed293752202416e6a1f1c9478f0a90 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 10:58:53 +0200 Subject: [PATCH 0254/1537] added missing attribute columns to faction table --- apps/esmtool/record.cpp | 8 ++++---- apps/opencs/model/tools/factioncheck.cpp | 2 +- apps/opencs/model/world/data.cpp | 2 ++ apps/openmw/mwdialogue/filter.cpp | 4 ++-- apps/openmw/mwgui/stats_window.cpp | 4 ++-- components/esm/loadfact.cpp | 2 +- components/esm/loadfact.hpp | 2 +- 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 8f77e4b445..d15e7f2b0b 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -679,10 +679,10 @@ void Record::print() std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; if (mData.mData.mUnknown != -1) std::cout << " Unknown: " << mData.mData.mUnknown << std::endl; - std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttributes[0]) - << " (" << mData.mData.mAttributes[0] << ")" << std::endl; - std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttributes[1]) - << " (" << mData.mData.mAttributes[1] << ")" << std::endl; + std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0]) + << " (" << mData.mData.mAttribute[0] << ")" << std::endl; + std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1]) + << " (" << mData.mData.mAttribute[1] << ")" << std::endl; for (int i = 0; i != 6; i++) if (mData.mData.mSkills[i] != -1) std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) diff --git a/apps/opencs/model/tools/factioncheck.cpp b/apps/opencs/model/tools/factioncheck.cpp index ea4a87eec8..af26904efa 100644 --- a/apps/opencs/model/tools/factioncheck.cpp +++ b/apps/opencs/model/tools/factioncheck.cpp @@ -29,7 +29,7 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector& messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); // test for invalid attributes - if (faction.mData.mAttributes[0]==faction.mData.mAttributes[1] && faction.mData.mAttributes[0]!=-1) + if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) { std::ostringstream stream; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc6cc01220..d62fd7267b 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -60,6 +60,8 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); mFactions.addColumn (new NameColumn); + mFactions.addColumn (new AttributesColumn (0)); + mFactions.addColumn (new AttributesColumn (1)); mFactions.addColumn (new HiddenColumn); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index ddb15d423d..78969ffd0b 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -569,8 +569,8 @@ bool MWDialogue::Filter::hasFactionRankSkillRequirements (const MWWorld::Ptr& ac MWMechanics::CreatureStats& stats = MWWorld::Class::get (actor).getCreatureStats (actor); - return stats.getAttribute (faction.mData.mAttributes[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && - stats.getAttribute (faction.mData.mAttributes[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; + return stats.getAttribute (faction.mData.mAttribute[0]).getBase()>=faction.mData.mRankData[rank].mAttribute1 && + stats.getAttribute (faction.mData.mAttribute[1]).getBase()>=faction.mData.mRankData[rank].mAttribute2; } bool MWDialogue::Filter::hasFactionRankReputationRequirements (const MWWorld::Ptr& actor, diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 86019fa28d..0678e98919 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -500,8 +500,8 @@ void StatsWindow::updateSkillArea() text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttributes[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttributes[1]); + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); assert(attr1 && attr2); text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp index 12a76f1ade..e2712d462d 100644 --- a/components/esm/loadfact.cpp +++ b/components/esm/loadfact.cpp @@ -71,7 +71,7 @@ void Faction::save(ESMWriter &esm) void Faction::blank() { mName.clear(); - mData.mAttributes[0] = mData.mAttributes[1] = 0; + mData.mAttribute[0] = mData.mAttribute[1] = 0; mData.mUnknown = -1; mData.mIsHidden = 0; diff --git a/components/esm/loadfact.hpp b/components/esm/loadfact.hpp index edc4640bb1..891b996473 100644 --- a/components/esm/loadfact.hpp +++ b/components/esm/loadfact.hpp @@ -34,7 +34,7 @@ struct Faction struct FADTstruct { // Which attributes we like - int mAttributes[2]; + int mAttribute[2]; RankData mRankData[10]; From e8c32d0c3db7a77ed27db957e5b1d718bb2fd961 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 11:23:17 +0200 Subject: [PATCH 0255/1537] MWWorld::Player cleanup --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwscript/controlextensions.cpp | 1 + apps/openmw/mwworld/cellstore.hpp | 35 +---------------- apps/openmw/mwworld/livecellref.hpp | 45 ++++++++++++++++++++++ apps/openmw/mwworld/player.cpp | 31 +++++++++++++-- apps/openmw/mwworld/player.hpp | 33 ++++++---------- 6 files changed, 88 insertions(+), 59 deletions(-) create mode 100644 apps/openmw/mwworld/livecellref.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index beb0b9aadf..8a0030be42 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem + esmstore store recordcmp fallback actionrepair actionsoulgem livecellref ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 8d65dfdd5b..ac53b8ee25 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -12,6 +12,7 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/ptr.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 2e6b45bb7e..0cc111cde3 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -6,45 +6,12 @@ #include #include -#include "refdata.hpp" +#include "livecellref.hpp" #include "esmstore.hpp" struct C; namespace MWWorld { - class Ptr; - class ESMStore; - - /// A reference to one object (of any type) in a cell. - /// - /// Constructing this with a CellRef instance in the constructor means that - /// in practice (where D is RefData) the possibly mutable data is copied - /// across to mData. If later adding data (such as position) to CellRef - /// this would have to be manually copied across. - template - struct LiveCellRef - { - LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) - : mBase(b), mRef(cref), mData(mRef) - {} - - LiveCellRef(const X* b = NULL) - : mBase(b), mData(mRef) - {} - - // The object that this instance is based on. - const X* mBase; - - /* Information about this instance, such as 3D location and - rotation and individual type-dependent data. - */ - ESM::CellRef mRef; - - /// runtime-data - RefData mData; - }; - - template bool operator==(const LiveCellRef& ref, int pRefnum); /// A list of cell references template diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp new file mode 100644 index 0000000000..4c5efb861f --- /dev/null +++ b/apps/openmw/mwworld/livecellref.hpp @@ -0,0 +1,45 @@ +#ifndef GAME_MWWORLD_LIVECELLREF_H +#define GAME_MWWORLD_LIVECELLREF_H + +#include + +#include "refdata.hpp" + +namespace MWWorld +{ + class Ptr; + class ESMStore; + + /// A reference to one object (of any type) in a cell. + /// + /// Constructing this with a CellRef instance in the constructor means that + /// in practice (where D is RefData) the possibly mutable data is copied + /// across to mData. If later adding data (such as position) to CellRef + /// this would have to be manually copied across. + template + struct LiveCellRef + { + LiveCellRef(const ESM::CellRef& cref, const X* b = NULL) + : mBase(b), mRef(cref), mData(mRef) + {} + + LiveCellRef(const X* b = NULL) + : mBase(b), mData(mRef) + {} + + // The object that this instance is based on. + const X* mBase; + + /* Information about this instance, such as 3D location and + rotation and individual type-dependent data. + */ + ESM::CellRef mRef; + + /// runtime-data + RefData mData; + }; + + template bool operator==(const LiveCellRef& ref, int pRefnum); +} + +#endif diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index ea8a02dee9..3338f08edf 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -1,14 +1,13 @@ #include "player.hpp" - #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" + +#include "../mwworld/ptr.hpp" #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" -#include "esmstore.hpp" #include "class.hpp" namespace MWWorld @@ -25,12 +24,38 @@ namespace MWWorld playerPos[0] = playerPos[1] = playerPos[2] = 0; } + void Player::setCell (MWWorld::CellStore *cellStore) + { + mCellStore = cellStore; + } + + MWWorld::Ptr Player::getPlayer() + { + MWWorld::Ptr ptr (&mPlayer, mCellStore); + return ptr; + } + + void Player::setBirthSign (const std::string &sign) + { + mSign = sign; + } + + const std::string& Player::getBirthSign() const + { + return mSign; + } + void Player::setDrawState (MWMechanics::DrawState_ state) { MWWorld::Ptr ptr = getPlayer(); MWWorld::Class::get(ptr).getNpcStats(ptr).setDrawState (state); } + bool Player::getAutoMove() const + { + return mAutoMove; + } + void Player::setAutoMove (bool enable) { MWWorld::Ptr ptr = getPlayer(); diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index c985510917..dfaddf66a9 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -1,15 +1,20 @@ #ifndef GAME_MWWORLD_PLAYER_H #define GAME_MWWORLD_PLAYER_H -#include "../mwworld/cellstore.hpp" #include "../mwworld/refdata.hpp" -#include "../mwworld/ptr.hpp" +#include "../mwworld/livecellref.hpp" #include "../mwmechanics/drawstate.hpp" +namespace ESM +{ + struct NPC; +} + namespace MWBase { class World; + class Ptr; } namespace MWWorld @@ -30,31 +35,17 @@ namespace MWWorld Player(const ESM::NPC *player, const MWBase::World& world); - void setCell (MWWorld::CellStore *cellStore) - { - mCellStore = cellStore; - } + void setCell (MWWorld::CellStore *cellStore); - MWWorld::Ptr getPlayer() - { - MWWorld::Ptr ptr (&mPlayer, mCellStore); - return ptr; - } + MWWorld::Ptr getPlayer(); - void setBirthSign(const std::string &sign) { - mSign = sign; - } + void setBirthSign(const std::string &sign); - const std::string &getBirthSign() const { - return mSign; - } + const std::string &getBirthSign() const; void setDrawState (MWMechanics::DrawState_ state); - bool getAutoMove() const - { - return mAutoMove; - } + bool getAutoMove() const; MWMechanics::DrawState_ getDrawState(); /// \todo constness From 8c7d578ddcf9a8d91e80c98618a19045252d1959 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:13:15 +0200 Subject: [PATCH 0256/1537] moved the CellRef struct to its own header --- apps/openmw/mwworld/livecellref.hpp | 2 +- components/CMakeLists.txt | 2 +- components/esm/cellref.hpp | 90 +++++++++++++++++++++++++++++ components/esm/loadcell.hpp | 78 +------------------------ 4 files changed, 93 insertions(+), 79 deletions(-) create mode 100644 components/esm/cellref.hpp diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 4c5efb861f..8f419b626f 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -1,7 +1,7 @@ #ifndef GAME_MWWORLD_LIVECELLREF_H #define GAME_MWWORLD_LIVECELLREF_H -#include +#include #include "refdata.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 88bf764445..a2f416fcca 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlock loadprob loadrepa loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist variant variantimp loadtes3 + loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref ) add_component_dir (misc diff --git a/components/esm/cellref.hpp b/components/esm/cellref.hpp new file mode 100644 index 0000000000..fb03a90844 --- /dev/null +++ b/components/esm/cellref.hpp @@ -0,0 +1,90 @@ +#ifndef OPENMW_ESM_CELLREF_H +#define OPENMW_ESM_CELLREF_H + +#include + +#include "defs.hpp" + +namespace ESM +{ + class ESMWriter; + + /* Cell reference. This represents ONE object (of many) inside the + cell. The cell references are not loaded as part of the normal + loading process, but are rather loaded later on demand when we are + setting up a specific cell. + */ + + class CellRef + { + public: + + int mRefnum; // Reference number + std::string mRefID; // ID of object being referenced + + float mScale; // Scale applied to mesh + + // The NPC that owns this object (and will get angry if you steal + // it) + std::string mOwner; + + // I have no idea, looks like a link to a global variable? + std::string mGlob; + + // ID of creature trapped in this soul gem (?) + std::string mSoul; + + // ?? CNAM has a faction name, might be for objects/beds etc + // belonging to a faction. + std::string mFaction; + + // INDX might be PC faction rank required to use the item? Sometimes + // is -1, which I assume means "any rank". + int mFactIndex; + + // For weapon or armor, this is the remaining item health. + // For tools (lockpicks, probes, repair hammer) it is the remaining uses. + int mCharge; + + // Remaining enchantment charge + float mEnchantmentCharge; + + // This is 5 for Gold_005 references, 100 for Gold_100 and so on. + int mGoldValue; + + // For doors - true if this door teleports to somewhere else, false + // if it should open through animation. + bool mTeleport; + + // Teleport location for the door, if this is a teleporting door. + Position mDoorDest; + + // Destination cell for doors (optional) + std::string mDestCell; + + // Lock level for doors and containers + int mLockLevel; + std::string mKey, mTrap; // Key and trap ID names, if any + + // This corresponds to the "Reference Blocked" checkbox in the construction set, + // which prevents editing that reference. + // -1 is not blocked, otherwise it is blocked. + signed char mReferenceBlocked; + + // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. + int mDeleted; + + // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza + // Brindisi Dorom", where it has the value 100. Also only for + // activators. + int mFltv; + int mNam0; + + // Position and rotation of this object within the cell + Position mPos; + + void save(ESMWriter &esm); + }; +} + +#endif \ No newline at end of file diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index afc953f54c..44412b5eb9 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -7,95 +7,19 @@ #include "esmcommon.hpp" #include "defs.hpp" - +#include "cellref.hpp" namespace MWWorld { class ESMStore; } - namespace ESM { class ESMReader; class ESMWriter; -/* Cell reference. This represents ONE object (of many) inside the - cell. The cell references are not loaded as part of the normal - loading process, but are rather loaded later on demand when we are - setting up a specific cell. - */ -class CellRef -{ -public: - int mRefnum; // Reference number - std::string mRefID; // ID of object being referenced - - float mScale; // Scale applied to mesh - - // The NPC that owns this object (and will get angry if you steal - // it) - std::string mOwner; - - // I have no idea, looks like a link to a global variable? - std::string mGlob; - - // ID of creature trapped in this soul gem (?) - std::string mSoul; - - // ?? CNAM has a faction name, might be for objects/beds etc - // belonging to a faction. - std::string mFaction; - - // INDX might be PC faction rank required to use the item? Sometimes - // is -1, which I assume means "any rank". - int mFactIndex; - - // For weapon or armor, this is the remaining item health. - // For tools (lockpicks, probes, repair hammer) it is the remaining uses. - int mCharge; - - // Remaining enchantment charge - float mEnchantmentCharge; - - // This is 5 for Gold_005 references, 100 for Gold_100 and so on. - int mGoldValue; - - // For doors - true if this door teleports to somewhere else, false - // if it should open through animation. - bool mTeleport; - - // Teleport location for the door, if this is a teleporting door. - Position mDoorDest; - - // Destination cell for doors (optional) - std::string mDestCell; - - // Lock level for doors and containers - int mLockLevel; - std::string mKey, mTrap; // Key and trap ID names, if any - - // This corresponds to the "Reference Blocked" checkbox in the construction set, - // which prevents editing that reference. - // -1 is not blocked, otherwise it is blocked. - signed char mReferenceBlocked; - - // Track deleted references. 0 - not deleted, 1 - deleted, but respawns, 2 - deleted and does not respawn. - int mDeleted; - - // Occurs in Tribunal.esm, eg. in the cell "Mournhold, Plaza - // Brindisi Dorom", where it has the value 100. Also only for - // activators. - int mFltv; - int mNam0; - - // Position and rotation of this object within the cell - Position mPos; - - void save(ESMWriter &esm); -}; - /* Moved cell reference tracking object. This mainly stores the target cell of the reference, so we can easily know where it has been moved when another plugin tries to move it independently. From 5244362fba72d6e47e54a75b9d6a5e890d8bb266 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:23:06 +0200 Subject: [PATCH 0257/1537] some cleanup --- apps/openmw/mwworld/cellstore.hpp | 1 - apps/openmw/mwworld/livecellref.hpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 0cc111cde3..7e4fc407d4 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -9,7 +9,6 @@ #include "livecellref.hpp" #include "esmstore.hpp" -struct C; namespace MWWorld { diff --git a/apps/openmw/mwworld/livecellref.hpp b/apps/openmw/mwworld/livecellref.hpp index 8f419b626f..28c1bb5c27 100644 --- a/apps/openmw/mwworld/livecellref.hpp +++ b/apps/openmw/mwworld/livecellref.hpp @@ -39,7 +39,7 @@ namespace MWWorld RefData mData; }; - template bool operator==(const LiveCellRef& ref, int pRefnum); +// template bool operator==(const LiveCellRef& ref, int pRefnum); } #endif From 111ebf84bb352072e60cc94e7e7427872b66aa91 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:27:57 +0200 Subject: [PATCH 0258/1537] replaced an include with a forward declaration --- apps/openmw/mwscript/locals.cpp | 13 ++++++++----- apps/openmw/mwscript/locals.hpp | 10 +++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwscript/locals.cpp b/apps/openmw/mwscript/locals.cpp index 2cf2a97c1d..180a2791bc 100644 --- a/apps/openmw/mwscript/locals.cpp +++ b/apps/openmw/mwscript/locals.cpp @@ -1,8 +1,11 @@ #include "locals.hpp" +#include + +#include + #include "../mwbase/environment.hpp" #include "../mwbase/scriptmanager.hpp" -#include namespace MWScript { @@ -39,9 +42,9 @@ namespace MWScript } return 0; } - + bool Locals::setVarByInt(const std::string& script, const std::string& var, int val) - { + { Compiler::Locals locals = MWBase::Environment::get().getScriptManager()->getLocals(script); int index = locals.getIndex(var); char type = locals.getType(var); @@ -51,10 +54,10 @@ namespace MWScript { case 's': mShorts.at (index) = val; break; - + case 'l': mLongs.at (index) = val; break; - + case 'f': mFloats.at (index) = val; break; } diff --git a/apps/openmw/mwscript/locals.hpp b/apps/openmw/mwscript/locals.hpp index 1d9b9c3e4f..deae0d44ea 100644 --- a/apps/openmw/mwscript/locals.hpp +++ b/apps/openmw/mwscript/locals.hpp @@ -3,9 +3,13 @@ #include -#include #include +namespace ESM +{ + struct Script; +} + namespace MWScript { class Locals @@ -14,11 +18,11 @@ namespace MWScript std::vector mShorts; std::vector mLongs; std::vector mFloats; - + void configure (const ESM::Script& script); bool setVarByInt(const std::string& script, const std::string& var, int val); int getIntVar (const std::string& script, const std::string& var); ///< if var does not exist, returns 0 - + }; } From 62d70f17c859977ac631378595cdf09b18022258 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 12:42:38 +0200 Subject: [PATCH 0259/1537] removed another redundant include --- apps/openmw/mwworld/cellstore.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 7e4fc407d4..f8467c84f6 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -1,8 +1,6 @@ #ifndef GAME_MWWORLD_CELLSTORE_H #define GAME_MWWORLD_CELLSTORE_H -#include - #include #include From 18e046e6285f41b588fba796da123a44faffeae0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 13:50:36 +0200 Subject: [PATCH 0260/1537] cleaned up race record struct --- apps/esmtool/record.cpp | 60 ++++++------------- .../mwmechanics/mechanicsmanagerimp.cpp | 16 +---- components/esm/loadrace.cpp | 9 +++ components/esm/loadrace.hpp | 13 ++-- 4 files changed, 34 insertions(+), 64 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index d15e7f2b0b..a6f77862ef 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1099,53 +1099,29 @@ void Record::print() template<> void Record::print() { + static const char *sAttributeNames[8] = + { + "Strength", "Intelligence", "Willpower", "Agility", + "Speed", "Endurance", "Personality", "Luck" + }; + std::cout << " Name: " << mData.mName << std::endl; std::cout << " Description: " << mData.mDescription << std::endl; std::cout << " Flags: " << raceFlags(mData.mData.mFlags) << std::endl; - std::cout << " Male:" << std::endl; - std::cout << " Strength: " - << mData.mData.mStrength.mMale << std::endl; - std::cout << " Intelligence: " - << mData.mData.mIntelligence.mMale << std::endl; - std::cout << " Willpower: " - << mData.mData.mWillpower.mMale << std::endl; - std::cout << " Agility: " - << mData.mData.mAgility.mMale << std::endl; - std::cout << " Speed: " - << mData.mData.mSpeed.mMale << std::endl; - std::cout << " Endurance: " - << mData.mData.mEndurance.mMale << std::endl; - std::cout << " Personality: " - << mData.mData.mPersonality.mMale << std::endl; - std::cout << " Luck: " - << mData.mData.mLuck.mMale << std::endl; - std::cout << " Height: " - << mData.mData.mHeight.mMale << std::endl; - std::cout << " Weight: " - << mData.mData.mWeight.mMale << std::endl; + for (int i=0; i<2; ++i) + { + bool male = i==0; - std::cout << " Female:" << std::endl; - std::cout << " Strength: " - << mData.mData.mStrength.mFemale << std::endl; - std::cout << " Intelligence: " - << mData.mData.mIntelligence.mFemale << std::endl; - std::cout << " Willpower: " - << mData.mData.mWillpower.mFemale << std::endl; - std::cout << " Agility: " - << mData.mData.mAgility.mFemale << std::endl; - std::cout << " Speed: " - << mData.mData.mSpeed.mFemale << std::endl; - std::cout << " Endurance: " - << mData.mData.mEndurance.mFemale << std::endl; - std::cout << " Personality: " - << mData.mData.mPersonality.mFemale << std::endl; - std::cout << " Luck: " - << mData.mData.mLuck.mFemale << std::endl; - std::cout << " Height: " - << mData.mData.mHeight.mFemale << std::endl; - std::cout << " Weight: " - << mData.mData.mWeight.mFemale << std::endl; + std::cout << (male ? " Male:" : " Female:") << std::endl; + + for (int i=0; i<8; ++i) + std::cout << " " << sAttributeNames[i] << ": " + << mData.mData.mAttributeValues[i].getValue (male) << std::endl; + + std::cout << " Height: " << mData.mData.mHeight.getValue (male) << std::endl; + std::cout << " Weight: " << mData.mData.mWeight.getValue (male) << std::endl; + } for (int i = 0; i != 7; i++) // Not all races have 7 skills. diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index c8d8279210..8757213e99 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -53,21 +53,9 @@ namespace MWMechanics for (int i=0; i<8; ++i) { - const ESM::Race::MaleFemale *attribute = 0; - switch (i) - { - case 0: attribute = &race->mData.mStrength; break; - case 1: attribute = &race->mData.mIntelligence; break; - case 2: attribute = &race->mData.mWillpower; break; - case 3: attribute = &race->mData.mAgility; break; - case 4: attribute = &race->mData.mSpeed; break; - case 5: attribute = &race->mData.mEndurance; break; - case 6: attribute = &race->mData.mPersonality; break; - case 7: attribute = &race->mData.mLuck; break; - } + const ESM::Race::MaleFemale& attribute = race->mData.mAttributeValues[i]; - creatureStats.getAttribute(i).setBase ( - static_cast (male ? attribute->mMale : attribute->mFemale)); + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); } for (int i=0; i<27; ++i) diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 139ef081c0..94aa792bc6 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -5,6 +5,15 @@ namespace ESM { + int Race::MaleFemale::getValue (bool male) const + { + return male ? mMale : mFemale; + } + + int Race::MaleFemaleF::getValue (bool male) const + { + return male ? mMale : mFemale; + } void Race::load(ESMReader &esm) { diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 91a424c10b..845956686c 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -26,11 +26,15 @@ struct Race struct MaleFemale { int mMale, mFemale; + + int getValue (bool male) const; }; struct MaleFemaleF { float mMale, mFemale; + + int getValue (bool male) const; }; enum Flags @@ -45,14 +49,7 @@ struct Race SkillBonus mBonus[7]; // Attribute values for male/female - MaleFemale mStrength, - mIntelligence, - mWillpower, - mAgility, - mSpeed, - mEndurance, - mPersonality, - mLuck; + MaleFemale mAttributeValues[8]; // The actual eye level height (in game units) is (probably) given // as 'height' times 128. This has not been tested yet. From 97d617d43f0bb88d680ddab826ee158d6f73c5e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 04:33:56 -0700 Subject: [PATCH 0261/1537] Use more appropriate VBO settings Unskinned meshes don't need dynamic VBOs; they aren't rewritten since their transformations are handled by the modelview matrix. They also don't need the local RAM copy (the "shadow buffer") since it's really only useful for skinning purposes (though this means the VBO has to be readable for static geometry to work). --- components/nifogre/ogrenifloader.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f8eca821ff..6083238808 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -845,8 +845,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; std::vector srcNorms = data->normals; + Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; + bool vertShadowBuffer = false; if(skin != NULL) { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. mesh->setSkeletonName(mName); @@ -948,8 +953,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcVerts.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, - true); + srcVerts.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); @@ -960,8 +964,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcNorms.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, - true); + srcNorms.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); @@ -980,8 +983,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader rs->convertColourValue(clr, &colorsRGB[i]); } vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, - true); + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); bind->setBinding(nextBuf++, vbuf); @@ -993,7 +995,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); + Ogre::HardwareBuffer::HBU_STATIC); for(size_t i = 0;i < numUVs;i++) { const std::vector &uvlist = data->uvlist[i]; @@ -1009,7 +1011,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(srcIdx.size()) { ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); + Ogre::HardwareBuffer::HBU_STATIC); ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); sub->indexData->indexBuffer = ibuf; sub->indexData->indexCount = srcIdx.size(); From ee0a20f9ce30cd885a3110df97b6e911095d5d7f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 07:00:24 -0700 Subject: [PATCH 0262/1537] Read some missing particle data from NIFs --- components/nif/data.hpp | 13 +++++++++---- components/nif/nifstream.hpp | 6 ++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 9bdba63961..68ffd19b8f 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -167,6 +167,10 @@ class NiAutoNormalParticlesData : public ShapeData public: int activeCount; + float activeRadius; + + std::vector sizes; + void read(NIFStream *nif) { ShapeData::read(nif); @@ -174,14 +178,13 @@ public: // Should always match the number of vertices activeCount = nif->getUShort(); - // Skip all the info, we don't support particles yet - nif->getFloat(); // Active radius ? + activeRadius = nif->getFloat(); nif->getUShort(); // Number of valid entries in the following arrays ? if(nif->getInt()) { // Particle sizes - nif->skip(activeCount * sizeof(float)); + nif->getFloats(sizes, activeCount); } } }; @@ -189,6 +192,8 @@ public: class NiRotatingParticlesData : public NiAutoNormalParticlesData { public: + std::vector rotations; + void read(NIFStream *nif) { NiAutoNormalParticlesData::read(nif); @@ -198,7 +203,7 @@ public: // Rotation quaternions. I THINK activeCount is correct here, // but verts (vertex number) might also be correct, if there is // any case where the two don't match. - nif->skip(activeCount * 4*sizeof(float)); + nif->getQuaternions(rotations, activeCount); } } }; diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index 02b931b7ed..a2595d17b8 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -168,6 +168,12 @@ public: for(size_t i = 0;i < vec.size();i++) vec[i] = getVector4(); } + void getQuaternions(std::vector &quat, size_t size) + { + quat.resize(size); + for(size_t i = 0;i < quat.size();i++) + quat[i] = getQuaternion(); + } }; } From 2f6ae4a915e1a26f75afd6993dd0b06ab40a211b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 3 Apr 2013 20:56:35 -0700 Subject: [PATCH 0263/1537] Read more particle information --- components/nif/controller.hpp | 79 ++++++++++++++++++++++++++++++++--- components/nif/data.hpp | 18 ++++---- components/nif/recordptr.hpp | 1 + 3 files changed, 82 insertions(+), 16 deletions(-) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 8331b93b7d..2ff25a274b 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -62,20 +62,87 @@ public: } }; -class NiBSPArrayController : public Controller +class NiParticleSystemController : public Controller { public: + float velocity; + float velocityRandom; + + float verticalDir; // 0=up, pi/2=horizontal, pi=down + float verticalAngle; + float horizontalDir; + float horizontalAngle; + + float size; + float startTime; + float stopTime; + + float emitRate; + float lifetime; + float lifetimeRandom; + + int emitFlags; // Bit 0: Emit Rate toggle bit (0 = auto adjust, 1 = use Emit Rate value) + Ogre::Vector3 offsetRandom; + + NodePtr emitter; + + int numParticles; + int activeCount; + //std::vector particles; /*numParticles*/ + + RecordPtr modifier; + void read(NIFStream *nif) { Controller::read(nif); - // At the moment, just skip it all - nif->skip(111); - int s = nif->getUShort(); - nif->skip(15 + s*40); + velocity = nif->getFloat(); + velocityRandom = nif->getFloat(); + verticalDir = nif->getFloat(); + verticalAngle = nif->getFloat(); + horizontalDir = nif->getFloat(); + horizontalAngle = nif->getFloat(); + /*normal?*/ nif->getVector3(); + /*color?*/ nif->getVector4(); + size = nif->getFloat(); + startTime = nif->getFloat(); + stopTime = nif->getFloat(); + nif->getChar(); + emitRate = nif->getFloat(); + lifetime = nif->getFloat(); + lifetimeRandom = nif->getFloat(); + + emitFlags = nif->getUShort(); + offsetRandom = nif->getVector3(); + + emitter.read(nif); + + /* Unknown Short, 0? + * Unknown Float, 1.0? + * Unknown Int, 1? + * Unknown Int, 0? + * Unknown Short, 0? + */ + nif->skip(16); + + numParticles = nif->getUShort(); + activeCount = nif->getUShort(); + nif->skip(numParticles*40); + + nif->getUInt(); /* -1? */ + modifier.read(nif); + nif->getUInt(); /* -1? */ + nif->getChar(); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + emitter.post(nif); + modifier.post(nif); } }; -typedef NiBSPArrayController NiParticleSystemController; +typedef NiParticleSystemController NiBSPArrayController; class NiMaterialColorController : public Controller { diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 68ffd19b8f..a2c9bb56db 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -165,9 +165,9 @@ public: class NiAutoNormalParticlesData : public ShapeData { public: - int activeCount; + float particleSize; - float activeRadius; + int activeCount; std::vector sizes; @@ -176,15 +176,15 @@ public: ShapeData::read(nif); // Should always match the number of vertices - activeCount = nif->getUShort(); + nif->getUShort(); - activeRadius = nif->getFloat(); - nif->getUShort(); // Number of valid entries in the following arrays ? + particleSize = nif->getFloat(); + activeCount = nif->getUShort(); if(nif->getInt()) { // Particle sizes - nif->getFloats(sizes, activeCount); + nif->getFloats(sizes, vertices.size()); } } }; @@ -200,10 +200,8 @@ public: if(nif->getInt()) { - // Rotation quaternions. I THINK activeCount is correct here, - // but verts (vertex number) might also be correct, if there is - // any case where the two don't match. - nif->getQuaternions(rotations, activeCount); + // Rotation quaternions. + nif->getQuaternions(rotations, vertices.size()); } } }; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea124..b7cd122bcb 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -142,6 +142,7 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; +typedef RecordPtrT RecordPtr; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT NiUVDataPtr; From ac10c5f05cd94034d3ee6b4a0ed97dc9518a8fc9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 01:26:57 -0700 Subject: [PATCH 0264/1537] Even more particle information --- components/nif/controlled.hpp | 8 +++++--- components/nif/controller.hpp | 29 ++++++++++++++++++++++++----- components/nif/recordptr.hpp | 1 - 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 36c9a82ace..08c47defee 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -66,12 +66,14 @@ typedef Named NiSequenceStreamHelper; class NiParticleGrowFade : public Controlled { public: + float growTime; + float fadeTime; + void read(NIFStream *nif) { Controlled::read(nif); - - // Two floats. - nif->skip(8); + growTime = nif->getFloat(); + fadeTime = nif->getFloat(); } }; diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index 2ff25a274b..aa6a9ef4ff 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -65,6 +65,14 @@ public: class NiParticleSystemController : public Controller { public: + struct Particle { + Ogre::Vector3 velocity; + float lifetime; + float lifespan; + float timestamp; + int vertex; + }; + float velocity; float velocityRandom; @@ -88,9 +96,9 @@ public: int numParticles; int activeCount; - //std::vector particles; /*numParticles*/ + std::vector particles; - RecordPtr modifier; + ExtraPtr extra; void read(NIFStream *nif) { @@ -127,10 +135,21 @@ public: numParticles = nif->getUShort(); activeCount = nif->getUShort(); - nif->skip(numParticles*40); + + particles.resize(numParticles); + for(size_t i = 0;i < particles.size();i++) + { + particles[i].velocity = nif->getVector3(); + nif->getVector3(); /* unknown */ + particles[i].lifetime = nif->getFloat(); + particles[i].lifespan = nif->getFloat(); + particles[i].timestamp = nif->getFloat(); + nif->getUShort(); /* unknown */ + particles[i].vertex = nif->getUShort(); + } nif->getUInt(); /* -1? */ - modifier.read(nif); + extra.read(nif); nif->getUInt(); /* -1? */ nif->getChar(); } @@ -139,7 +158,7 @@ public: { Controller::post(nif); emitter.post(nif); - modifier.post(nif); + extra.post(nif); } }; typedef NiParticleSystemController NiBSPArrayController; diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index b7cd122bcb..c5bafea124 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -142,7 +142,6 @@ class NiSourceTexture; class NiRotatingParticlesData; class NiAutoNormalParticlesData; -typedef RecordPtrT RecordPtr; typedef RecordPtrT NodePtr; typedef RecordPtrT ExtraPtr; typedef RecordPtrT NiUVDataPtr; From 77ba0fbe730ff6d9e7a20126df177054d183eed2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 01:31:05 -0700 Subject: [PATCH 0265/1537] Prepare for creating particles This adds a vector of ParticleSystems to the EntityList, and modifies corresponding code to handle it. It also loads the ParticleFX plugin so particles can be created (although they aren't yet). --- apps/openmw/mwrender/animation.cpp | 3 +++ apps/openmw/mwrender/npcanimation.cpp | 6 +++--- apps/openmw/mwrender/objects.cpp | 13 ++++++++++++- components/nifogre/ogrenifloader.hpp | 4 +++- libs/openengine/ogre/renderer.cpp | 1 + 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cc926e685d..fd575f9183 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -40,9 +40,12 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < mEntityList.mParticles.size();i++) + sceneMgr->destroyParticleSystem(mEntityList.mParticles[i]); for(size_t i = 0;i < mEntityList.mEntities.size();i++) sceneMgr->destroyEntity(mEntityList.mEntities[i]); } + mEntityList.mParticles.clear(); mEntityList.mEntities.clear(); mEntityList.mSkelBase = NULL; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b76a38c469..f1af6a7d3c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -363,11 +363,11 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) assert(&entities != &mEntityList); Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + for(size_t i = 0;i < entities.mParticles.size();i++) + sceneMgr->destroyParticleSystem(entities.mParticles[i]); for(size_t i = 0;i < entities.mEntities.size();i++) - { - entities.mEntities[i]->detachFromParent(); sceneMgr->destroyEntity(entities.mEntities[i]); - } + entities.mParticles.clear(); entities.mEntities.clear(); entities.mSkelBase = NULL; } diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 50c0210649..8c5d4cad3a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -156,7 +158,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || anyTransparency) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || + anyTransparency || entities.mParticles.size() > 0) { for(size_t i = 0;i < entities.mEntities.size();i++) { @@ -169,6 +172,14 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } + for(size_t i = 0;i < entities.mParticles.size();i++) + { + Ogre::ParticleSystem *part = entities.mParticles[i]; + // TODO: Check the particle system's material for actual transparency + part->setRenderQueueGroup(RQG_Alpha); + part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); + part->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); + } } else { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 92b153468a..e6672541bd 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -40,8 +40,10 @@ namespace NifOgre typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct EntityList { - std::vector mEntities; Ogre::Entity *mSkelBase; + std::vector mEntities; + + std::vector mParticles; EntityList() : mSkelBase(0) { } diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 309ba8a060..05760ffa98 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -195,6 +195,7 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "RenderSystem_GL3Plus", *mRoot); Files::loadOgrePlugin(pluginDir, "RenderSystem_Direct3D9", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); + Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) From b5719e0ec7051d139de32023577c630124842c9f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 4 Apr 2013 05:08:12 -0700 Subject: [PATCH 0266/1537] Create particle systems for NiAutoNormalParticles and NiRotatingParticles nodes Very incomplete, but it's something to work with. --- components/nifogre/ogrenifloader.cpp | 171 +++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6083238808..6d08d4ffcc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -317,7 +319,9 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape /* Handled in the mesh loader */ + node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles )) warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); @@ -326,7 +330,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } @@ -588,7 +593,8 @@ static std::string findTextureName(const std::string &filename) } public: -static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String &name, const Ogre::String &group, +static Ogre::String getMaterial(const Nif::ShapeData *shapedata, + const Ogre::String &name, const Ogre::String &group, const Nif::NiTexturingProperty *texprop, const Nif::NiMaterialProperty *matprop, const Nif::NiAlphaProperty *alphaprop, @@ -617,7 +623,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String int specFlags = 0; Ogre::String texName[7]; - bool vertexColour = (shape->data->colors.size() != 0); + bool vertexColour = (shapedata->colors.size() != 0); // Texture if(texprop) @@ -819,12 +825,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader std::string mGroup; size_t mShapeIndex; - void warn(const std::string &msg) + static void warn(const std::string &msg) { std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; } - void fail(const std::string &msg) + static void fail(const std::string &msg) { std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; abort(); @@ -1039,9 +1045,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } bool needTangents=false; - std::string matname = NIFMaterialLoader::getMaterial(shape, mesh->getName(), mGroup, + std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, - vertprop, zprop, specprop, needTangents); + vertprop, zprop, specprop, + needTangents); if(matname.length() > 0) sub->setMaterialName(matname); @@ -1114,6 +1121,146 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static LoaderMap sLoaders; + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) + { + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, + partctrl->velocity+partctrl->velocityRandom); + emitter->setEmissionRate(partctrl->emitRate); + emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, + partctrl->lifetime+partctrl->lifetimeRandom); + + Nif::ExtraPtr e = partctrl->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiParticleGrowFade) + { + // TODO: Implement + } + else if(e->recType == Nif::RC_NiParticleColorModifier) + { + // TODO: Implement (Ogre::ColourInterpolatorAffector?) + } + else if(e->recType == Nif::RC_NiGravity) + { + // TODO: Implement (Ogre::LinearForceAffector?) + } + else + warn("Unhandled particle modifier "+e->recName); + e = e->extra; + } + } + + Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, + const Nif::Node *partnode) + { + const Nif::NiAutoNormalParticlesData *particledata = NULL; + if(partnode->recType == Nif::RC_NiAutoNormalParticles) + particledata = static_cast(partnode)->data.getPtr(); + else if(partnode->recType == Nif::RC_NiRotatingParticles) + particledata = static_cast(partnode)->data.getPtr(); + + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); + try { + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + if(partnode->parent) + { + // FIXME: We should probably search down the whole tree instead of just the parent + const Nif::PropertyList &proplist = partnode->parent->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + } + const Nif::PropertyList &proplist = partnode->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + + bool needTangents; + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + needTangents)); + + partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->activeCount); + + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) + { + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) + entitybase->attachObjectToBone(partctrl->emitter->name, partsys); + } + ctrl = ctrl->next; + } + + if(!partsys->isAttached()) + entitybase->attachObjectToBone(partnode->name, partsys); + } + catch(std::exception &e) { + std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); + partsys = NULL; + }; + return partsys; + } + + NIFMeshLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1199,6 +1346,14 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } + if((node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01)) + { + Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); + if(partsys != NULL) + entities.mParticles.push_back(partsys); + } + const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { From 73da794d77c8d2552bf478478f43b54e4c45d028 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 4 Apr 2013 14:34:39 +0200 Subject: [PATCH 0267/1537] added basic race table --- apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadrace.cpp | 21 +++++++++++++++++++++ components/esm/loadrace.hpp | 3 +++ 9 files changed, 64 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d62fd7267b..c596bb162d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -66,11 +66,17 @@ CSMWorld::Data::Data() for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn (i)); + mRaces.addColumn (new StringIdColumn); + mRaces.addColumn (new RecordStateColumn); + mRaces.addColumn (new NameColumn); + mRaces.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); + addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); } CSMWorld::Data::~Data() @@ -129,6 +135,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getFactions() return mFactions; } +const CSMWorld::IdCollection& CSMWorld::Data::getRaces() const +{ + return mRaces; +} + +CSMWorld::IdCollection& CSMWorld::Data::getRaces() +{ + return mRaces; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -168,6 +184,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; + case ESM::REC_RACE: mRaces.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 16a9685a53..6b729728f5 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -26,6 +27,7 @@ namespace CSMWorld IdCollection mSkills; IdCollection mClasses; IdCollection mFactions; + IdCollection mRaces; std::vector mModels; std::map mModelIndex; @@ -62,6 +64,10 @@ namespace CSMWorld IdCollection& getFactions(); + const IdCollection& getRaces() const; + + IdCollection& getRaces(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 985cab0d4c..2e5e6a0a0a 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -22,6 +22,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -33,6 +34,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Skill, "Skill" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0190467c4b..2213e15f31 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -43,7 +43,9 @@ namespace CSMWorld Type_Classes, Type_Class, Type_Factions, - Type_Faction + Type_Faction, + Type_Races, + Type_Race }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 83b333c04e..e12929cf2e 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -101,6 +101,10 @@ void CSVDoc::View::setupWorldMenu() QAction *factions = new QAction (tr ("Factions"), this); connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView())); world->addAction (factions); + + QAction *races = new QAction (tr ("Races"), this); + connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); + world->addAction (races); } void CSVDoc::View::setupUi() @@ -271,6 +275,11 @@ void CSVDoc::View::addFactionsSubView() addSubView (CSMWorld::UniversalId::Type_Factions); } +void CSVDoc::View::addRacesSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Races); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 03905430a8..4132d73b20 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -121,6 +121,8 @@ namespace CSVDoc void addClassesSubView(); void addFactionsSubView(); + + void addRacesSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index de36594a58..d5ba273776 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -19,6 +19,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Globals, CSMWorld::UniversalId::Type_Classes, CSMWorld::UniversalId::Type_Factions, + CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadrace.cpp b/components/esm/loadrace.cpp index 94aa792bc6..955424e2b9 100644 --- a/components/esm/loadrace.cpp +++ b/components/esm/loadrace.cpp @@ -30,4 +30,25 @@ void Race::save(ESMWriter &esm) esm.writeHNOString("DESC", mDescription); } + void Race::blank() + { + mName.clear(); + mDescription.clear(); + + mPowers.mList.clear(); + + for (int i=0; i<7; ++i) + { + mData.mBonus[i].mSkill = -1; + mData.mBonus[i].mBonus = 0; + } + + for (int i=0; i<8; ++i) + mData.mAttributeValues[i].mMale = mData.mAttributeValues[i].mFemale = 1; + + mData.mHeight.mMale = mData.mHeight.mFemale = 1; + mData.mWeight.mMale = mData.mWeight.mFemale = 1; + + mData.mFlags = 0; + } } diff --git a/components/esm/loadrace.hpp b/components/esm/loadrace.hpp index 845956686c..6ecec8ebb9 100644 --- a/components/esm/loadrace.hpp +++ b/components/esm/loadrace.hpp @@ -66,6 +66,9 @@ struct Race void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } From 48a88f1917d00eccb9c2e490f13f3dc335c240be Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Apr 2013 15:10:27 +0200 Subject: [PATCH 0268/1537] Fix startRandomTitle --- apps/openmw/mwsound/soundmanagerimp.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwsound/soundmanagerimp.cpp b/apps/openmw/mwsound/soundmanagerimp.cpp index 1b07dfe627..69e3016767 100644 --- a/apps/openmw/mwsound/soundmanagerimp.cpp +++ b/apps/openmw/mwsound/soundmanagerimp.cpp @@ -208,14 +208,21 @@ namespace MWSound void SoundManager::startRandomTitle() { - Ogre::StringVectorPtr filelist; - filelist = mResourceMgr.findResourceNames(Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - "Music/"+mCurrentPlaylist+"/*"); - if(!filelist->size()) + Ogre::StringVector filelist; + + Ogre::StringVector groups = Ogre::ResourceGroupManager::getSingleton().getResourceGroups (); + for (Ogre::StringVector::iterator it = groups.begin(); it != groups.end(); ++it) + { + Ogre::StringVectorPtr resourcesInThisGroup = mResourceMgr.findResourceNames(*it, + "Music/"+mCurrentPlaylist+"/*"); + filelist.insert(filelist.end(), resourcesInThisGroup->begin(), resourcesInThisGroup->end()); + } + + if(!filelist.size()) return; - int i = rand()%filelist->size(); - streamMusicFull((*filelist)[i]); + int i = rand()%filelist.size(); + streamMusicFull(filelist[i]); } bool SoundManager::isMusicPlaying() From 2e7d5377f40b257186f21e939e370e298c5b51f9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 4 Apr 2013 16:51:22 +0200 Subject: [PATCH 0269/1537] Fix crash when moving npcs to an inactive cell --- apps/openmw/mwrender/renderingmanager.cpp | 2 +- .../mwscript/transformationextensions.cpp | 4 ++-- apps/openmw/mwworld/scene.cpp | 14 +++++------ apps/openmw/mwworld/worldimp.cpp | 24 ++++++++++++++----- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 2f49a40316..cd5ab19b9d 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -235,7 +235,7 @@ void RenderingManager::cellAdded (MWWorld::Ptr::CellStore *store) mObjects.buildStaticGeometry (*store); mDebugging->cellAdded(store); if (store->mCell->isExterior()) - mTerrainManager->cellAdded(store); + mTerrainManager->cellAdded(store); waterAdded(store); } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 000cc545db..97dc6d7188 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -304,7 +304,7 @@ namespace MWScript } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWWorld::Class::get(ptr).adjustPosition(ptr); } else { @@ -343,7 +343,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWWorld::Class::get(ptr).adjustPosition(ptr); } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index c8853f4842..2244a4fc64 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -115,11 +115,6 @@ namespace MWWorld if(result.second) { - /// \todo rescale depending on the state of a new GMST - insertCell (*cell, true); - - mRendering.cellAdded (cell); - float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; @@ -142,6 +137,11 @@ namespace MWWorld } } + /// \todo rescale depending on the state of a new GMST + insertCell (*cell, true); + + mRendering.cellAdded (cell); + mRendering.configureAmbient(*cell); mRendering.requestMap(cell); mRendering.configureAmbient(*cell); @@ -166,7 +166,7 @@ namespace MWWorld float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); - world->adjustPosition(player); + MWWorld::Class::get(player).adjustPosition(player); } MWBase::MechanicsManager *mechMgr = @@ -358,7 +358,7 @@ namespace MWWorld float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayer().getPlayer(), x, y, z); - world->adjustPosition(world->getPlayer().getPlayer()); + MWWorld::Class::get(world->getPlayer().getPlayer()).adjustPosition(world->getPlayer().getPlayer()); return; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2ce753b816..ae9b7a06b7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -706,6 +706,7 @@ namespace MWWorld void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); + pos.pos[0] = x; pos.pos[1] = y; pos.pos[2] = z; @@ -718,7 +719,7 @@ namespace MWWorld if (*currCell != newCell) { - removeContainerScripts(ptr); + removeContainerScripts(ptr); if (isPlayer) { @@ -750,7 +751,7 @@ namespace MWWorld else { MWWorld::Ptr copy = - MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + MWWorld::Class::get(ptr).copyToCell(ptr, newCell, pos); mRendering->updateObjectCell(ptr, copy); @@ -780,12 +781,14 @@ namespace MWWorld bool World::moveObjectImp(const Ptr& ptr, float x, float y, float z) { CellStore *cell = ptr.getCell(); + if (cell->isExterior()) { int cellX, cellY; positionToIndex(x, y, cellX, cellY); cell = getExterior(cellX, cellY); } + moveObject(ptr, *cell, x, y, z); return cell != ptr.getCell(); @@ -827,6 +830,19 @@ namespace MWWorld { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); + if(!ptr.getRefData().getBaseNode()) + { + // will be adjusted when Ptr's cell becomes active + return; + } + + float terrainHeight = mRendering->getTerrainHeightAt(pos); + + if (pos.z < terrainHeight) + pos.z = terrainHeight+400; // place slightly above. will snap down to ground with code below + + ptr.getRefData().getPosition().pos[2] = pos.z; + if (!isFlying(ptr)) { Ogre::Vector3 traced = mPhysics->traceDown(ptr); @@ -834,10 +850,6 @@ namespace MWWorld pos.z = traced.z; } - float terrainHeight = mRendering->getTerrainHeightAt(pos); - if (pos.z < terrainHeight) - pos.z = terrainHeight; - moveObject(ptr, pos.x, pos.y, pos.z); } From 01314b7c08e25ca4376e38bb97fc148e0217a208 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Fri, 5 Apr 2013 12:08:35 +0200 Subject: [PATCH 0270/1537] addin more nomadic icons --- files/opencs/raster/activator.png | Bin 0 -> 2297 bytes files/opencs/raster/apparatus.png | Bin 1864 -> 1580 bytes files/opencs/raster/creature.png | Bin 0 -> 2506 bytes files/opencs/raster/leveled-creature.png | Bin 0 -> 2212 bytes files/opencs/raster/lockpick.png | Bin 0 -> 679 bytes files/opencs/raster/probe.png | Bin 0 -> 583 bytes files/opencs/raster/random-item.png | Bin 1612 -> 1993 bytes files/opencs/raster/repair.png | Bin 1474 -> 1280 bytes files/opencs/scalable/top-level/.directory | 5 + files/opencs/scalable/top-level/gmst.svg | 1047 +++++++++++++++++ .../scalable/top-level/topic-regular.svg | 1045 ++++++++++++++++ 11 files changed, 2097 insertions(+) create mode 100644 files/opencs/raster/activator.png create mode 100644 files/opencs/raster/creature.png create mode 100644 files/opencs/raster/leveled-creature.png create mode 100644 files/opencs/raster/lockpick.png create mode 100644 files/opencs/raster/probe.png create mode 100644 files/opencs/scalable/top-level/.directory create mode 100644 files/opencs/scalable/top-level/gmst.svg create mode 100644 files/opencs/scalable/top-level/topic-regular.svg diff --git a/files/opencs/raster/activator.png b/files/opencs/raster/activator.png new file mode 100644 index 0000000000000000000000000000000000000000..0446af22cf7d4238e06d7682ab5ec86127b103c8 GIT binary patch literal 2297 zcmZ{lX*ARi7sr2+b!?S2`22n@r05bxw9> z^a&3Bmx+@u2Id9;@G%8)gk@vqEIv0)41tP1iIu;TIOI)p00=$@0Fguh_{}UuE(3rc z2mq^20HB=-03u$wjn;5xgZ;jl34%$c9T+u5Fu~=8wDV!EKK$z}kN}Mw0O06FAq;FW zly$VLSNgD6cnjljqh$tyiWEP+dLoMS><*1|p{VYgzjG-~6k=+-Tw27pJha7ule}iJ zCjHo-@1Xm~92G#P9X3(>6-s7(vyD7E^(R zY|+H&S)R1roK?+@EQ}5zxj=k?*TJtLS8B4(0LhYFtdwhEGFBDkQ_??mI8^AuH!gID4Sc&3jLI6eP)tANo{PpG~ zaSm&o4Q=0&PfBZ$R67^YrGvI?xmQh7k17<5#{Iyk(x-J43&iRoQPZs6|=c~?~hpWO<)=%C!K4rHq0*w?(Z zOC7`(HWg9=q|J4gPT|rJLH50I$Zb{m>(J6qH** z;dZl6nk-)HhLtzN`6@^G<#C2L5n2$7PHJ~2W*Llvw0!=N3Xu)rCJ08YJdw$~&q&n8!U7?6S7tH0Um~iLog$FC%$~rzyzd zvfo@`qXO`LBSGVy1fHixQF0gKQWA`A32wqu($dlna2G#U{+w+3Gq%HBBl(zo13KOf z-l!a1;>{F0!(a^q%~^@37a&2P)2x5U9HHq{5;3eeD+()`F}UbtW=56ai4&d2AiepB z0wfp*>a=P(j4yAAP{>$tIkrk|l;De4)8qFz(Q@?cc)uh-_?hU{LPXkv(j{s%c6C{L zIR?AjlX|22uF3}(;Pc|wj0|D=?=wHA#-~&t4V8|3CJ3dl%myEZyjlBQ+g`Xb z;3p||IVMz>-}HQ`Lu6ZGDuU~^h_-l8o=9|iTO2|z%dF(v;cE+%hIucUFb$8ron7f$ z5~lHmP`>0ve|NWu@53V#4+Jkpka>lkP8py7A|4y%eg!h9Ua-cl?9l9-do5%mzS^bF z1C8d5eJqpnMK((!5^oJkOpf|*ZhD4Pgktlw2;QqSh?}%JPxWwN-IuMS|CB^n2h7Cp z_RnlIe0#S(-Smh4XGdaiY{)ABwbH{Mde5LDG*b*3jK=LyH9C*t;xzfVQ@FPv-tI1rlDjxq?EYBlwLw^!DnfrR@Cm1rW$W&R2uH zttxR3)!8%fUyoNlrYE|+g0B*SHCvnK(~IZ0>vcJ99R)9Pbk!=LWFw=BT^W2`26E3u z4GTb+=~JG;p}>3kGNR=`U*p);x$u7SzN{B|&UTv!R-76axHpn}NnkM0Q?fX+!N&7}ZvfUC4+I1RD7!v(^TA=g@XDUvE;$?Uv& literal 0 HcmV?d00001 diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png index 613030267620c5a7680dec1cacb012a6cdc7e5d7..037ed290fe9d5fd538bd21f9eda35f83d5048069 100644 GIT binary patch delta 1547 zcmV+m2K4#J4y+82Bnkm@Qb$4nuFf3kks%X*32;bRa{vGf5&!@T5&_cPe*6Fc02*{f zSaefwW^{L9a%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000G>Nkl%ilj80$5+v+~wjEsV4FD4J??VGdK*?aA^_Q(5j)v7OKfud=nF?3F;5SIhs zdGhdrm6GzZvYqJdJ&D9b{hP3LG9Ql;2n-O_H#X*Dc6JzN&lW+Yl8$(k0JR_`FE0ag zbGPvDp##au5q~L_VzZ}6@Q46EEiGn$c6_`G&!11gYAu8+STgG|0t`r}Q%u`zHB^QB zxOJ-o+qat$tn@GR1PM;@^x_ewgX!r}+`n%_eSI!fLHviu2n5MQ*5cwUJb2*1Cci$wpW#k+5uxz{aF-ByBKY!+Jf| z(@9L!!EDyToS;F1Nexqc7~k!NT61W!S`MBnrAX;U6(Ickox;*1bcArUN@L2-M-z4v9WfH zj$XjXNGl2S9JS^w3A70V17~pcY6EPxQtoZ7{rn7#bbBfCey*|g>6rjXD0x_GgFv0*MYa;)r5r`_!@ zXW%DK{)(KOjgSWsfpCLzj){=<-08gP*0R3^KYsidWM^-HRO&s)1rh7b%*^j3uaOje>z#P9Z#N&xkYeG!AnbjKth5HLcy9^wvencnbZq? zeKp*ujgMdctZH9>3SL(BBlhgEkN|xa81~yVoMIocICeU(eYR2i5ID=1j0_zFe6J~% z#2f*I+~53dY9!5b6=yPIW1atd&Q}6wuMZ0ofY0~h_RhsH68rm37Zqia;k0oM$0GT^ zn#@YzhYn>@<|yIqy?XlXwzWurc0eDMN<3dt@iPgLxnM7U?DkXt+Tm6LFDc1FW~Lq@ z(VBUoz-#f};JL6ehi$AomBeu0`-2!ySwJH-!MPX z+IkkLOszvhRxVh2da6I^?Vkdd2YJK$o7MG87v1*=u>VA*!f!q;EdslDuSY>aIz?>_ zmuf6-R|=MYkM(@>W)1BW0nqD(WISH;3}eL#goKDUF>sdY4##PV&U%W@TFU+=E>gR@ ztCpqOhrlZx2US(s+;YpTmpw+K@r6j}wP{5HfdPE8#iFG+Jw{6@d-3vRf?dwq z!{+(Ok?(Q%@HQ}Y7Zz^eK=Si9p}2S(*hC#XxCIAx4y1G0zjJ2-LPOWWXYK0ue*2bb zKq~QllbWhS3hjaxi<;K7FeD|dqZKWLN~xmtESPLmiTHRqt!6>AmdOwk9e}7PDU3!5 xtz%+Z#r$9}h`6%rw0!R6YPAmof3s8re*;>O4EKC1no$4%002ovPDHLkV1nah delta 1849 zcmV-92gdlU49E_UB!2{FK}|sb0I`n?{9y$E0004VQb$4nuFf3k0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv00000008+zyMF)x z010qNS#tmY4f_B94f_ELcQu;;00tOIL_t(o!@ZVmh+J10$AACl<=&Z{$?QzBlV)}{ zBu&T*DQSF3X(0Vz(nb-*60{mbD3q28C5t3bKZzhg@rw{@G6XD$_#wz*P}?YBD~Qw} zwhKzl+E(H=-DbPHnH^_$cJ}VQ=bY#9!@YN$jM?1@*dBPeGw0kn|KIa}o_p>HY%pG} z)wZ^c*+R?}Eq~?qxkh6!tM$lo5M+c9^IM087Ja4W9q^$977DrCd!K*qIlIxm=@4rz zymIN%(e~=FLpz$HsoT9)Rkd*!SRruhuSK{>)z|C$;Z+$oM`oo_AOH zo(E5B_)0-*-GNh5LIP;ET6pdHb-%oM^ONUJpKkneeEctK0qEX|Jv(+B4OUm-YYjgY zQwqM;(0^J(NeLwcAOx5hjtG_r#uykWV@nf<7Me|A!|-tcKkggAwpw#PID58o`RY}? zd-EndrI7Lc7$_-+k`h9Q*nT2J)FFEmmEeB><{OQ< zHc&bF#1nAGk7J?P#LcNGv{zOjr35<{_W&~(fPat@ju}cRRJLuy-d($JX#akI2tlg_ zBAUG~fIF?087!4RL>MZUarDtgkmVmvuBjCSsgz5%x8^UvqA*+FuyW2+DXLds6aq~nEB05fFQnn;>cBqbti z=f8R3!kxYVjvYHDvRZ!yK-}5Rp;Rcu07*z8Af<%V8d51x(huGDq)&mhmcrH5*Ra8m z>4(*&r3Z!zg#$zcV{N>7Vr80D#|5S0Lw~6!`;G$uf>w)#5Wm<6pyNO(mm6ka3lYIt z3j*R=cV%^#3n@U?dVGnm%gyHBTU!62Z-5|*4hz6{&Vl3l+l*4W<3K8sI3cwLr0mS0 z3u1Y3(OP3Jzj*$<>$?Ow-~TL_1vv+6E#~X>YfJUI>HUF7vXtqm*E5{8n7?&v#eW&| z(njKU0SGBSk)CWp81j2_a~JBjZ~v*iw8UVJZ%PgyCPL~|@0gvMiiqf`(-$uWeFIdh z)r=NmhjR{56rtH_&AmP`agD9L&}uX+5Wo2t05gM_K?y(_NW#lz6@Za`#5({Z3?+uh`>Z3=RnqihyWs_4l#i8$cWNf*J`7qyZZw8 zYhChq?uEiIT6TOIBUVqb>=&e0IGZU4hW@w|MHnL zdP4vq7qhb`CDt*wcC-S18Et8mC!OdS4RM<3ide`C`$_6^rL;XU+_--viA5bVOvGgRvHo zG5GYMLmJ6O+>?2y1jcl}vvYSjls+8;`Meguv+DuqiOI>=k3RhHuO;v~2!SAqu5i1( zv%R$RnD%|e-L+5ccMd{`PJbDQ=)Vpy15t$CV`IG9Y=*nve!KcC@WZ4@f13gR*bUG* zOO6~o_$kL6e*2+^{s91uYV{jR>mTJxrQ*==u(zdJm8EhSem)QFdGS9Y=U~DR!SXU% zjRx*aPn&QuV2|VJNwrD8#h`EjNfCsp947GC0^eU;2uCqFngZXJ~7+! z%uE0PC&$LF0C>DBvBDZ#EG5^v0KRp<`s@w%Ck*iQ|EqWx#I-)ePkkifT@b%p z2jHt8sdyK})q99P^?$L5cR~E7OZ>|pt9Td0r3g5=*7|<{JnFP0r1W5t0000bbVXQn zWMOn=I%9HWVRU5xGB7bSEif}JGci;#Fgh?cIyEvYFfuwYF!;jw!~g&QC3HntbYx+4 zWjbwdWNBu305UK!Gc7PPEi*AxF)%tXHaayjD=;!TFffUqKr(m$000?uMObuGZ)S9N nVRB^vcXxL#X>MzCV_|S*E^l&Yo9;Xs00000NkvXXu0mjffHPMs diff --git a/files/opencs/raster/creature.png b/files/opencs/raster/creature.png new file mode 100644 index 0000000000000000000000000000000000000000..52c41615adece79dfabeb4ff91ce1a40fc125754 GIT binary patch literal 2506 zcmV;*2{rbKP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000R&Nkl&0tN@bMn&hz>-)QjA$5&w34?I}#)EM6`$x zn>Pty2P^^rdNif4Sj`$K(1uJZmb#y#-Djb(*o;9)er*<8e4K9CNi4z|3TRw=#nP zKQlW5yJ8JU^Yz9ilNLvkjaW$n_)0Is?${u7lluo8Ay^k8N2n*~7m76{0QyISOx$;f z0RE*S3BwI@@o2>yCUXjYy*Li1G9$3fqGKq(SDl5vVh00$GRuNPNugM+_r*?|4u_nf z*q;!Lz3~Q|Otav4iW%FZ{IO6jfR@MZo2ZRXL}>LDOYOdrSKlUE&`*H-2?HZ*itu!8 zDITqwhu(S7=pnVI=fTokCVL9ronc~Vr$8TNP|f5>+a|f^bz3mg|V1zHo$7oVU0a-oc76? zFAdjVmfj!EAR;z!a4r5*{@fIR0B^h56u!%LNf@?5qk(r#t+@W`^#t?@7R*MGff_;%A@PMA< zF~yvwFc9r4db&3*gvp$OUn@<-^2mU3aDz-V1)Qp#);vHYV1f_}g(wQ}VZb+=RM<#Z zD3fsD&vt)0MFW%;laFYK>6`eAE?23yQ( zEYo_!!1Wk*Gy8}}uNTJSd7}$|-&TWHtyLJ^T#4t+OLL-eF~^4ealxon3!z|pjJlEf zkM`!pV0c9?UNo2C`z4upP@RE+$~5#50VY|3uxXhKKYrhfESni7F`<)8wH%U>OUg$9 zp)}o_0}G!8gC`dbqYho$R$^X?1r~of_Bq2yzy@@Z3Hc{t(>sWcCMJ64zF zVBeM%IMvaJ&UF>Ahxwzf(1{R*c%1f4;YxgCRA4R9#~d$r$XV{^-9GyNF*15@lMze( zpW1I*dIXjiCF9YxF63n-;`Gi2{BY+ChHjq3gDYLQd+`8np6SGupk}$hQnJ33GCnZT|1aj*81J7?YIw1u0dIaD z!SJI&M1<;bbjuR-9^FDf+drK5;HNqpakzCE{@hf~fa^6f9B6I8g@c<=J1-G&M94Jr zh5#}0KY&YF?#x^mH=+n1Z>d=#9H}F;A4~{CHd#J;4>V)!rzdzj_8R?tConJDiL8W3 zl+TVuU6B(t1rAh_ske|!y&Ojv;v#~O5<_PH2k`IqHe<#7RG3K_Dr7vwalU|($WKO{;GfQ1b&`JdFRBR6d?A|b=X~?)^fb#XJ9V_wEvjP0`<+E{c zs)N7YIDrR!UAWhC5O>b)#f{S)(}Ex0@kcDmjfF-c{P%Q&=#vsmjLazY9w`YAAk@a< zArai@;{hh~-wVED%>qP)Xke9iLCIy0%xE0j6w-!`wop7=lmdG&F`cg$;r`_#zZ<-B z-C~qvSfTTwd!mZ*3N4rQ`4U9>N(Ot0upTeV#?XceB!=rqJ0{^oM-y(J-Sb)64{WZ( z+NxY6MFt|6*!g;5z0`iI$vmJt!DlrPt&qN;*8F5uK7QP=klBn~+wC7ZK@v|fAEd+(YXt_F=`4_4TtNM!$BI^Xs|~1E?h1` zo=%2V0z46XLzseCujlmpz~lg|zLM?@kp`U3h{AR*Ai}_gTFF|9F3{Avx>-~ub`0|lRJV3*8Klj-Z&(U U?%gBa9RL6T07*qoM6N<$f*UxK2mk;8 literal 0 HcmV?d00001 diff --git a/files/opencs/raster/leveled-creature.png b/files/opencs/raster/leveled-creature.png new file mode 100644 index 0000000000000000000000000000000000000000..4aa2c56cd7bfc3407f8aa7a56830089ccc022461 GIT binary patch literal 2212 zcmV;V2wV4wP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000ORNkl3WL7}&?` z?##~a&OX^)*ar)Xd3ud8VDm5-f(Z~1et>c8`cc1=l1A8x8as-U_*KPmqE@2qk6Lcj z)>VI0RVC+FDc{Bj zJFLw`PV3E5j}ou++Q%#N?BgXaTRfo1qXt1p{W^?q1w3DoueU|>ac*}je*FENxN`hC zynC__7Y}ygU_%-5EYkg;Vs_3&;(sO(b=j^QYO27`UKzrfoy}-3$;UdceX^y<_s>Jk zmAG`I3&*xr!7YoQ{9g!^xRv`qKeG=98p`3bnkRya+{{3fcEN8o-{>v#vGv`lOmA7U0GB*^LD*{Pgs0#C(p)fL^@ow@Qx%B#C0PD2g{|j!Tj>MKkCgMuP!%s|=?sLNW+{Opda^ zD&5>)A4OkP5KhT-aTWnqFDduIsm>a_Hq?d}``&?eotnhalfWs_Q-=_4iI zCQmTh2<-72A&VxVzGcq1EbLhtyYV)v@|C1DP{O~RbI!`v&BBN7kW@l<;}NB6O@@j zCX&KtG16U&58gV0U!FgXa|b$bdRG$~%0p^Y94&)amV{AW6hOe|LD27k-EMyz`E+m= zIuppu%tU&6I*BigcaHSn#qCWP-qnILLoL`-6G7N2PI)BbV2aNwUGFaO;f;OI;KGq^ z75s(njVSgxRS*WRE-S)dPb+p04q)Wy9$X}&Io7usZ5yI!Sr&I1NgmvyVS@WL)ghVgZ1UMKSRKZ98cQ)) z8$q$#s)~ziURx2t)}~Fkefu`HwYTBYu^u&3KcHv^J2qo*U>Ejp??TjTM{aJe3eM3p zfp!A_^j8<~`}ari?)P@!^?e<9iO6@a&4W)A#vd!vZ8l!@%f?T_76Sri0eL3jfhd|D zvB*jz1=!PBi*2oqxNy85Cuo7*&1HDGe={0tH>kwgTU$^U@xY+dV)g3PDtK0A2Hrcp z7r(ju0^U5h4I?`maJ;h`dmGoH$tS~Y)Wzqt;)HrhP@^m=MNtsU_afkR!RxXk-{XM8 zW>M2#AN8ZLt_Gz+KWvf-85tQ^xpF0zELnm)*@R0+yK(+-*9`EkQZGtnEo=te=)8LY zk-1L7nlg~#u*#DKM?DXVNubCzShZ>umM&e2RjH}S&Cb46?2xB=qIuX`U#yn)xpJQx zd7-FpS&&y=pXE-!*I2s4C~d?Zy#v%2NrL1o$XBJNp{1 zLDuWcGaElHkc|k*26#mQPNVK)0)K4DDgibJwouwOU+$?XfzxdI?Q|0K*Of#m*zt&v zYB;&1b`6P+`kfsR(_4^A5l^h)G6@qsWj<{5n4uW;ugx%`0!2Q&w{`uW2b!wlA(!n> z>qB|}8lpX15e=Uuv_OELbL!dgxHVZ5>=E20?0#mmSuKxh#YBu}&PIA#+GPeK0@t>N z?ARJoI0L_)L7>oKefv~@BYyJg9$cpWeyO(}yX%TUFF~)<{e#A5G#)YVlfZdn;xcgu zPzh8qk{%v0m|_&JHh3j$30UDUBoWvj3#V2D-1mli>ha1zGfsBZpnrW3HX^`L@}fNE z1LqR4P+1d9g7vX@@nZE1U^nW=S}FP(r-8*cIwJ#oQ|7ej3vJSseAyT;amj!2$;O8U zZLXS124{Esy0oiX@>k%j0q%qZiG>Rn!eY>$4M}=DQ|v-W)W9KVW3vd%byOlz?VvGE z0{c77UvQn1Yn}|wk*l>Q7v#=ZuwVf^Cf(GQpbfPi5jH_LHt&guA0W{kqPkD9x;YD+ z0Upx@mjL(MWYiQ=f3FQdHhif8Cb4MIA_$pjXp1<|;HLwNpuKAmbdhgL;8vpT=2CkC z+)B>ZK)}5liZR@^5d(Em33e3yHEyS5a3;ldW?iu0 z_`1Mh!N~STygJy7!|m%Jkt1>mSO-Q;&O@u9yZ+SQ1wFXPbkVuSilq^05r~6w;wk^bho(CND z5FI)z+%iOpo;AQ3;CXd=`qY0-fRsPXdpp;giO}`EAaSA%Rt%K%A~s^>gjB$XKW&W}Ir-WVllpn3YedznhbtJ;`3cSy-`R1shTH zNhD_NhTL`uW8tF}?|hsAwpIe0v61k?l$omp%9{9yhLfHfXELfG(U|WeXBGiU{X+(3 zB0Lh;91#(i^eED*9d#30A_S7Yymty>3LEG$y6kVL6W7Wq=h#ygk_46%A m&qe5+4{4pd$=?8Tz55@NYw_ktWMjYp0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv0006ONklS0#WHT=4)>aYX}=;EDwx#T5yFR>drnW$aGCFKv6tu@`48mdEXzWvR028>m`cTodH}}@g#!3} zzR!T)9~Ar6{QD$T0LSzBJXnv8KDhNZli-pnz{dxJ0U(@fwy_*sbO1iy@An~_&4SD6 zd}l(Tb<#Iq{7!HQa6FYtfz4`VH#auc0FK|rTa5ywPaDO)NG! zal7x;#J>aJIQnSVw^$?{Dx^Vm_!r9s!%Vfp=M``sAHP+rRVWsV5DErAxz8t}Lxs2k z;c)l`{ez(>>Vuo@#D@xT0Gg&>EoSrhKk)eyY;SFit}ZWSA1b63_yQjhWTXEyacuwq N002ovPDHLkV1g@2BNYGu literal 0 HcmV?d00001 diff --git a/files/opencs/raster/probe.png b/files/opencs/raster/probe.png new file mode 100644 index 0000000000000000000000000000000000000000..2e4c553279ecff5d4e7cf5d3d91984f06bc7d569 GIT binary patch literal 583 zcmV-N0=WH&P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv0005DNkl{|NlP&t+Aqlf`F%|=Rr4D z*9)#LE-R4jql@J}K0bGj9zFX1>eZ|N7c5xt-`?JS7t9efbpXicFw5`XzYli6;lqdj z7ZnxV1V&V6z+)3Y#}?{+|#Ze-9|HKr;v6v%I6D;RbMt5>i7f8f9Ya6X4+HT2YutF$G%96+|*(ZS)fzrX+6 zwQJY@U%!6+e_|~sI|R@zx3{yiO-f9ZcX4(;VPj)+!P?pyrM$;i*N_|n*es`{G9$?W z)V7?YD4>PqL_2_1mJ{UwT3Sxf0kpOpuLI~|IZg-A%W|v^pr_>+4xqQ?C=M71%TXKv zYO{lCHBiL@D%&Y3UP;jlE{Y=~BD`9fn?a4mpY*gG9s;1?4+#nRTvb^Ka>Nl*d_bvM zcx4nE6jW1MQu4nbKmWhEnHk+2fl?a=1_sW_&dU0qmYVwC#MqcFj=-pny}iBXBqk*M zkBN@{Z)jjZb4Orp54gIz&It_-{pRcA^WVtOa0;dIOje5s7zK6udU~KvqyQ})003gN VHPn4~U(x^o002ovPDHLkV1j(X_g4S_ literal 0 HcmV?d00001 diff --git a/files/opencs/raster/random-item.png b/files/opencs/raster/random-item.png index 349130abe5b47d0258e9abbbfb89acd51da39df8..0b2571422cdf1f9e396129f80a800dabef387d88 100644 GIT binary patch delta 1975 zcmV;o2T1tL49O3W85ITq0047(dh`GQ00DDSM?wIu&K&8HArpTIa7bBm000XT000XT z0n*)m`~Uy|8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900%fpL_t(o zN41yPQOP0{b*IQg36d>zW%J`A=v*d4o(5;o93G|ipx+{ebbOAD>)>D*a&-dC5SIYU4 z$S@5O_5|T%Ni?or%D}9|_t>3*5S=nYAEfwrdmxX2 z|NG-}nBLySyXk-6&164bkf1Jiro+d}b;4fwq5`0A_D~5^lJ~EFfA4w$e*0%VUKtz6 zYb&MOijcrnpL{j!k2-(u?~x(P;H&;4$V9Lg6U3r3;G=QN^3}S$ z)&+=v_fR;0()n>sKA!B4>-}9!S`XoSg@jxGe+hp;F6Buy9-?0|lE1~(?hIVJl!>mE zWTp%kniA2`d;piur6TP>FeGm5u}yl_pX~``!3=Nk{;@o+IF4b9|f z#k0qC7$2#@)BBY$+^fPbw@PudF9$yqML{X!&8*S5MJyD=yaAAg)BAagC(4VWac3YO zlfQq~lCJN?>xm&ukN4x{(>_d&cH#NsHar{o5u?K=@!;C`81BzSbLDPq&?!wyDX(R| zAZ!NkS+z^wt{DFh{T+v4B!=_Kc!A9SFlL?)l9@k86qjQ3P6<(6j7LL7csN+d!0%qo z!|lttxYe73_R|SShz*3R!08G7PFsO|6###6F$qcCSVeI(<8agCO$2-c?_S;|LG;1+ zb0u!{(|P)#M`GkTaqyLupBcJ-T2q55k~pMXftEA)hG7D%S#QZRLa1`VliA@T_F;QAd`QJ zQS@Cj%9a=Yk7`LI?x`tQL#V(U1f){A%kVTt1tM-ZROlDvUySh#Gv3;}t6>r1c>q zHq(3I5CeZdbDx1vkGGSQS1@o|^TdDnzga2w(W;S=5)O^0f`RjRJa9N1Y!CNmlz$2D zX-dMyhD6jC$6&Kw1*t2$+~S1ZUakXmC*#OyRTJ=SChaeNZLosVhV%4PS<+77KV3Xx zskw(*!ob;VHe7@}oA9o>{pdIqkBZz#Xq19C^tND;F>~G)p*4-%JcidVdKiD@w&1ke zJ=~R+n&)M1w`#bQ_zeu)+1VLRPEMAzo0Xg4?NxhlwmcSzF@BJXIkha6oZt21sl9kP zR?jGZW$gM&xp~yCbY$U7^#L?hC0N1x&ZR-6aI?VqJT_BvTky7%yKs&KP(U`P%#Hnk zwa#DqgxV^d^EZ=2bHZ)SdG>#yaO~Nkvw}N1IwEX?W?pzp*-ji!4~0auYJwFS;%*q~ z&ta5Pdo?%QLMBsNw%by3bJ{7K$6bZSvN)#UzD&DWIfXZu#Gp7M6rOUvfkj5oaOYYc z>Hc=c+wE~UI_EVdaaJ`q!>bBo7KAq*k3vz}#?Jw4)T;~wJz0#s(#3zWkaDxhR2Rou zYEI$N5xzKIv(GO0>B4QuPY!`X%rUY8*GQhwTkhGZyISK3GF6A0nYK5S$wSFH-{Ruq1S2O2gnQgD#jY$Xza)+O{47va%TC4WX zTXULrs+_`49gRTB4nKd0c;5`Lq+(9w-W>tBNml5S;WC?BZ8qHOaHU7LVRuv@j%ROK z6udk$6d`^R@YxP2%r06<}KW_GvFR$iSGhP2oK zxbdBs^PLI6T_Mni2CGeN_4}>%`CQ7W$x!8H__Afo5EJHY7d(HL)P9Xx_<^K9&gv?b zt>&a`3HAIyFPR&cvcFoXvlk0ZJ5^5MOP4N1Ug}21;mmVxOL@*d9oA{w;KFsZTuD~< z0LergIiY5blAl+N<#FgFW-`}Sqb5VsPL(eNr!`OA;SVo4-?UojT=3;l^3_GeoMS3s ztxC!p+e~(M@~(fiDE%%1Ww~2$>Ua!ljzyvB`|bE4e=D=qP8^9qX?7S&$PX22ug8eN z6dc@uTyh;BCZCPp>diEqfa5Sll*}$50Sx# zJl<*-gH|mxXjMW3S+52!g}^}FjT($v!hJ}`j65y2z-AZLe*lrQqikNLH*f#|002ov JPDHLkV1g>3&0GKg literal 1612 zcmZ`(X;4#F6uyB3Lc(4G1p{F-vIPT}$j}r42}@WhV^AGn&==Nvijd%jsxGa8f0J_;jomDf%A^dQJ z&d?E(7b3I_rt(nI`NGmZaOvnWSh_0@#m6er7H!v{p_4Tc< zukY*Y16|_;g1xGS8$sZ^>=CW8jNyu7$vZbwH4g+jsO@!sCvDwWE_#Dv4)@cI1J)z$g=c{ew= z#>U2`rl#fPgty-U-tC$6c!fJ>2w~C zx45|Y`0-=tUrS5t;lqbSB5`0~prxf{aBvXXtE#GkibX|5wY9ZNOH1wT?Ik58t*xz= zmX>X8Z9r~rZtm~zhrQ(GB~jmmmw{n11YO6&`4}dn;<-{8h9%Qtz_3XH^{7r9 zCX0i@YDtaT1{p-*o9gRXxuDF3uE02ne z>wgWq!X+FC4n)NS>ku&XGD2dq;FQ%Ty^bU2u&x4OBs9=p=>5A`utv@-II9 zs^HRv9Ytgjm6esH%tI0rp2tZ&f8)}!R(l4cZMW+#B4M#k^#`fsgDwTJQhDS2 zb-$z9bi&trs{71RBn9o+(&Z%sKmGjh6N$qy@K?r;`~LicF+sNJMAFh?DN6J0RK`@r4ck3# zL}zNNgZ(#39%Znr{a$rJLc;XaJG~Ug;r-Q@F0zzM-Q9vHO4aanLa3tZkr&)c&+hI! z4Lr)s%&;S_Aj)$$&53qUbRxF+*?HyE#ZUMn4Nk;Ao$8AN1os3nJjyldIsGUKQ~2at z{F5m`RCIko98SF7p+Z4F|IFMt<=l;w)Oo){rM*M#z4;{knM%^B+*CPfZEcsMd}dcf z1t+OXcuOG>To1cqC}fJ0#c9HprZ;s%JYLqbo~w67ldW74p~l?(NDID9^`(35QNu99 z1)l4nn_8AlYi86s+{o>L@6F4n26om@+%id+rI&9c6DN)zNK*}@jpW!~9F8d7aDNwD zoqIob^{?QSbzJF&zxQhIq(e&Rl}Xiig5OG8UwCWlc%L*4&_*pjEorRR7vOh_c1pP) zN)zLyNj~DtBmm^e^zdRZy%=5|LJy`7lkLOuc4d0{FquahYD)eSkd~e(Nk0Am0gQPX w8v-oV6$I(Y(wz9rB$Shr<1RUonkA0UNODilJa+XJ#|lU&lp7IvGeD&H8)U$05dZ)H diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png index a8165827790baac034005d1b4729b02ad45e5f70..5e495d8fd72c88a04aab96c5eb72ad11fb5ad9e4 100644 GIT binary patch delta 1256 zcmVN2bPDNB8b~7$DE-^4L^m3s900eJIL_t(o zN9|TePh4jdudlDgjdU{Ik?(UMStE=Sb==i6fpP%HXQb{WMpP%vd@sWJ!@Uz}tUXm9* z&&SilL-L@*@4CCWNp5twhO3K<FFtskB@P9c!-081MKbXVP|ItTU%S$*x10@ z+8S0?R>bp*i;I|_pU3R%ET*TYF*!Mj@$qqtj*en@co>6&gXr(?M^{%Df`Woz@#C{+ z@7LGYMd5$l-Ca?Xi$xIuF3hADaC>_jo12^9XZio-<>hOznVA_(O-%`~v9U3XjEo4N zfq?<^_4T2*w--G zLQ7<>SRPGCh){&DhJWu1o|%~mTN|5qG;lY74J5v5Lk9;3Exq)Chl%h1zTolk@gJ$< zUv7VkdXqUoFZS~+9335r!$ZhZeb+lDaM)N|>&@+%TM4ig6A}_oSy?Hp#n&-0F=2M# zN=r*w_I-2Ucisi0hK@qziv7z<7_4P#+9{kq(1d^YU<9}jrQi2jt@barB-_rU)%1E; zTUl+~1^mtm7>ZGpzU7?YkolU=>+9>0o}PaWit(gJA>gD?T=5`s!hIex3|?DXi?p;f z*xB0VJ~#nNF0D?d`@~nk@*5|d0lcQB2Ib}DpuqX*3+y;M$)P`hq}obhOxdya`uVSH(hNaPHn*=M2snP)19Kmk$pruU#h7 z-rf$bZI*yx4f6^$Wi?ZsGdQcpofi}ofVV7PM^;uAGBPrR8n+UluNwalT0%TbTp&L` zAGx`?$jQzYMR>8W%~DfSk)qQfDJg#miHV7bkBdWWY^>-olGZrOtqlu9XlN)j8V%I1 zULiO*7+jk%Om0K6*(qCzrEY3!LPJ9X>gwtQp{lAX@LJ{h;4X`bimtoNCW1_kEy%uCqb?q4Iv98h+!{f2W13e0umr3fsh19f+T22 z$bk?MWQ9l)2pE>2oGb^`sy%Df7VF8<_D*s1(cbm!AN}6veb@Vb?|sJ;2l$h0*Ep>U7^#B(;v@M+%+D*-d9-X=0IC#}EJUWoYJ_*W*JQ`Zl zpwhO~NaSJ;kDW?S4hZxQ2tJ(4J=JDxl2=LT%v4`r($1Ybsln8$8il^QwawU=LQlqc zWAeG|JZ?^XW38d9!!p=ovgngi60lgTgM$N+Ow3@UilxPMO*MEtrqk4+P@ZmV)~aii z3A8w4uTE!bj!ih`;^Gn=6E2kSHT7pzwF+)=UT8#M#L=*@s9;drDGn)IibzK+RO#n^p#wIYUHbY~p z;X==#VPtIJQcr7VZ=0#F!#rr{8!-=$4UFF!othr&9WwO|cTY`^Pu{++Ij^j)KclKs zsO!#Xv}aZ46w*p@NqLc=l*=v7&E;iD6=HLr(K2M#XqB9zoB}~kp_n6*6_!>A#j?Vp zk^*gW?X`)an|CH|-I*L3wHSJJJYgPRln>@vCKpO8OXO7&ae0wY!t3h4q&inAlJX@A zQAJf5=m?N(LD~m|oJsW$ged-$L%u#fBq9Otjq}1DJg{s1UKA3EL?GaBRL$Q@sT@~q+xk?@cR=0paDO$Ip}{90SEA=@RZwb|}!5J2<6dj)x3kB`~P z;GPy&RS7C3nnHQ0T6k7=3>zTw3d0BaMd7Hv5yTLG&f?|`N_5(rGJ6zlLbabZ8wIl_ z>`1f=c4ygA++O6oblHPlgQ=!c^}4o{Ceo$DXkRJ!eQZ+>1VmRobMjk`JwX3g{T{wCRd>&nOF zKiJwtud|MQbXV*ARejx^mS_`aXvFYET-;+OV)GUHz23y<#uxjtX7635%~{^rh-cPR zcsO}>{WkT;nIv;Mn7MfS8EQ0naTjf}`aXjLBM%5lbN57BDoPr*yX|*Ix$bk>yQi;K z*Vv`)Y;i2OIn~5fA^79la54P90IMH;i~s-t diff --git a/files/opencs/scalable/top-level/.directory b/files/opencs/scalable/top-level/.directory new file mode 100644 index 0000000000..464bddbfce --- /dev/null +++ b/files/opencs/scalable/top-level/.directory @@ -0,0 +1,5 @@ +[Dolphin] +PreviewsShown=true +Timestamp=2013,4,3,11,19,41 +Version=3 +ViewMode=1 diff --git a/files/opencs/scalable/top-level/gmst.svg b/files/opencs/scalable/top-level/gmst.svg new file mode 100644 index 0000000000..3b59a44fe9 --- /dev/null +++ b/files/opencs/scalable/top-level/gmst.svg @@ -0,0 +1,1047 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/opencs/scalable/top-level/topic-regular.svg b/files/opencs/scalable/top-level/topic-regular.svg new file mode 100644 index 0000000000..c972dfa18c --- /dev/null +++ b/files/opencs/scalable/top-level/topic-regular.svg @@ -0,0 +1,1045 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + From 076831c9cc5dc0bf9b9bc864eff82a4715856b7b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 5 Apr 2013 12:48:05 +0200 Subject: [PATCH 0271/1537] added flag columns to race table --- apps/opencs/model/world/columns.hpp | 34 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ 2 files changed, 36 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index dfabaaf2cf..ad6916ae2b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -434,6 +434,40 @@ namespace CSMWorld return true; } }; + + template + struct FlagColumn : public Column + { + int mMask; + + FlagColumn (const std::string& name, int mask) + : Column (name, ColumnBase::Display_Boolean), mMask (mask) + {} + + virtual QVariant get (const Record& record) const + { + return (record.get().mData.mFlags & mMask)!=0; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + int flags = record.get().mData.mFlags & ~mMask; + + if (data.toInt()) + flags |= mMask; + + record2.mData.mFlags = flags; + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c596bb162d..18ff5aac1a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -70,6 +70,8 @@ CSMWorld::Data::Data() mRaces.addColumn (new RecordStateColumn); mRaces.addColumn (new NameColumn); mRaces.addColumn (new DescriptionColumn); + mRaces.addColumn (new FlagColumn ("Playable", 0x1)); + mRaces.addColumn (new FlagColumn ("Beast Race", 0x2)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 35fe828108a2ab9b8f71071e3a9e1ec693e39d78 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 5 Apr 2013 13:46:48 +0200 Subject: [PATCH 0272/1537] added race table weight/height columns --- apps/opencs/model/world/columns.hpp | 40 ++++++++++++++++++++++++++++- apps/opencs/model/world/data.cpp | 4 +++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index ad6916ae2b..f65f212da1 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -453,7 +453,7 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - int flags = record.get().mData.mFlags & ~mMask; + int flags = record2.mData.mFlags & ~mMask; if (data.toInt()) flags |= mMask; @@ -468,6 +468,44 @@ namespace CSMWorld return true; } }; + + template + struct WeightHeightColumn : public Column + { + bool mMale; + bool mWeight; + + WeightHeightColumn (bool male, bool weight) + : Column (male ? (weight ? "Male Weight" : "Male Height") : + (weight ? "Female Weight" : "Female Height"), ColumnBase::Display_Float), + mMale (male), mWeight (weight) + {} + + virtual QVariant get (const Record& record) const + { + const ESM::Race::MaleFemaleF& value = + mWeight ? record.get().mData.mWeight : record.get().mData.mHeight; + + return mMale ? value.mMale : value.mFemale; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + ESM::Race::MaleFemaleF& value = + mWeight ? record2.mData.mWeight : record2.mData.mHeight; + + (mMale ? value.mMale : value.mFemale) = data.toFloat(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 18ff5aac1a..fb835b986a 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -72,6 +72,10 @@ CSMWorld::Data::Data() mRaces.addColumn (new DescriptionColumn); mRaces.addColumn (new FlagColumn ("Playable", 0x1)); mRaces.addColumn (new FlagColumn ("Beast Race", 0x2)); + mRaces.addColumn (new WeightHeightColumn (true, true)); + mRaces.addColumn (new WeightHeightColumn (true, false)); + mRaces.addColumn (new WeightHeightColumn (false, true)); + mRaces.addColumn (new WeightHeightColumn (false, false)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From dc9f5f93e74567acf0b3975e7328ba702bbd4003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 05:14:24 -0700 Subject: [PATCH 0273/1537] Use a helper function to get node properties --- components/nifogre/ogrenifloader.cpp | 155 ++++++++++----------------- 1 file changed, 56 insertions(+), 99 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6d08d4ffcc..4b0f9ce3dc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -836,15 +836,44 @@ class NIFMeshLoader : Ogre::ManualResourceLoader abort(); } + static void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop) + { + if(node->parent) + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop); + + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else + warn("Unhandled property type: "+pr->recName); + } + } // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -1044,7 +1073,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool needTangents=false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + bool needTangents = false; + + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, @@ -1061,42 +1098,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop) + bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node) { - // Scan the property list for material information - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) { - handleNiTriShape(mesh, dynamic_cast(node), texprop, matprop, alphaprop, vertprop, zprop, specprop); + handleNiTriShape(mesh, dynamic_cast(node)); return true; } @@ -1108,7 +1114,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(!children[i].empty()) { - if(findTriShape(mesh, children[i].getPtr(), texprop, matprop, alphaprop, vertprop, zprop, specprop)) + if(findTriShape(mesh, children[i].getPtr())) return true; } } @@ -1163,69 +1169,20 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); try { + std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + const Nif::NiTexturingProperty *texprop = NULL; const Nif::NiMaterialProperty *matprop = NULL; const Nif::NiAlphaProperty *alphaprop = NULL; const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; - if(partnode->parent) - { - // FIXME: We should probably search down the whole tree instead of just the parent - const Nif::PropertyList &proplist = partnode->parent->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; + bool needTangents = false; - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - } - const Nif::PropertyList &proplist = partnode->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - - bool needTangents; + getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, @@ -1280,7 +1237,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } const Nif::Node *node = dynamic_cast(nif->getRecord(0)); - findTriShape(mesh, node, NULL, NULL, NULL, NULL, NULL, NULL); + findTriShape(mesh, node); } void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) From 12fada28622c329b1119b6e5b6d0fae10e207eb7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 05:34:59 -0700 Subject: [PATCH 0274/1537] Don't offset the animation time to 0 --- components/nifogre/ogrenifloader.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4b0f9ce3dc..f663cdf145 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -167,7 +167,7 @@ static void fail(const std::string &msg) static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { - Ogre::Animation *anim = skel->createAnimation(name, stopTime-startTime); + Ogre::Animation *anim = skel->createAnimation(name, stopTime); for(size_t i = 0;i < ctrls.size();i++) { @@ -246,7 +246,7 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const } Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime-startTime); + kframe = nodetrack->createNodeKeyFrame(curtime); if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) kframe->setRotation(curquat); else @@ -441,16 +441,15 @@ void loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter = keyiter; + TextKeyMap::const_iterator insiter(keyiter); TextKeyMap groupkeys; do { sep = insiter->second.find(':'); if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first - keyiter->first, - insiter->second.substr(sep+2))); + groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first - keyiter->first, insiter->second)); + groupkeys.insert(std::make_pair(insiter->first, insiter->second)); } while(insiter++ != lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); From bf0ae3ae72bb5f0d291d037b41f326707f65b21c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 06:29:14 -0700 Subject: [PATCH 0275/1537] Read NiVisData info --- components/nif/data.hpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index a2c9bb56db..c13495ff8b 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -297,13 +297,17 @@ public: float time; char isSet; }; + std::vector mVis; void read(NIFStream *nif) { int count = nif->getInt(); - - /* Skip VisData */ - nif->skip(count*5); + mVis.resize(count); + for(size_t i = 0;i < mVis.size();i++) + { + mVis[i].time = nif->getFloat(); + mVis[i].isSet = nif->getChar(); + } } }; From 48d9885554cdddb7c813035f9d226228f91ac310 Mon Sep 17 00:00:00 2001 From: Glorf Date: Fri, 5 Apr 2013 15:42:05 +0200 Subject: [PATCH 0276/1537] Started bugfix #691 --- apps/openmw/mwclass/armor.cpp | 87 +++++++++++++++++++++ apps/openmw/mwclass/armor.hpp | 2 + apps/openmw/mwclass/clothing.cpp | 61 +++++++++++++++ apps/openmw/mwclass/clothing.hpp | 2 + apps/openmw/mwclass/weapon.cpp | 66 ++++++++++++++++ apps/openmw/mwclass/weapon.hpp | 2 + apps/openmw/mwmechanics/actors.cpp | 3 +- apps/openmw/mwworld/actionequip.cpp | 104 +------------------------ apps/openmw/mwworld/class.cpp | 5 ++ apps/openmw/mwworld/class.hpp | 3 + apps/openmw/mwworld/inventorystore.cpp | 6 +- apps/openmw/mwworld/inventorystore.hpp | 2 +- 12 files changed, 237 insertions(+), 106 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 320944d3ce..496e695450 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -16,6 +16,8 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/player.hpp" #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" @@ -290,6 +292,91 @@ namespace MWClass ref->mBase = record; } + bool Armor::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + + bool allow = true; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + { + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); + + allow = false; + break; + } + } + + if(!allow) + break; + } + + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + { + allow = false; + // Only notify the player, not npcs + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); + } + break; + } + } + + if(!allow) + return false; + } + + } + } + return true; + } + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 65f49abb7d..bb07e42b03 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,6 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + 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 abad267675..77a7557bf6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -14,6 +14,7 @@ #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/nullaction.hpp" +#include "../mwworld/player.hpp" #include "../mwgui/tooltips.hpp" @@ -237,6 +238,66 @@ namespace MWClass ref->mBase = record; } + bool Clothing::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + + // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) + const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); + if(race->mData.mFlags & ESM::Race::Beast) + { + if (*slot == MWWorld::InventoryStore::Slot_Boots) + { + bool allow = true; + std::vector parts; + if(it.getType() == MWWorld::ContainerStore::Type_Clothing) + parts = it->get()->mBase->mParts.mParts; + else + parts = it->get()->mBase->mParts.mParts; + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) + { + allow = false; + // Only notify the player, not npcs + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); + } + break; + } + } + + if(!allow) + return false; + } + + } + } + return true; + } + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index c3ef22f113..4978fa2288 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,6 +61,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + 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 0a527262f8..51e8130039 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,6 +384,72 @@ namespace MWClass ref->mBase = record; } + bool Weapon::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == item) + { + break; + } + } + + assert(it != invStore.end()); + + std::string npcRace = npc.get()->mBase->mRace; + + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) + { + if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + } + } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) + { + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + } + } + return true; + } + return false; + } + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const { boost::shared_ptr action(new MWWorld::ActionEquip(ptr)); diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4774bb50be..922cd165f2 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,6 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f60567c6c4..89671ee086 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -36,8 +36,7 @@ namespace MWMechanics void Actors::updateNpc (const MWWorld::Ptr& ptr, float duration, bool paused) { if (!paused && ptr.getRefData().getHandle()!="player") - MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip ( - MWWorld::Class::get (ptr).getNpcStats (ptr)); + MWWorld::Class::get (ptr).getInventoryStore (ptr).autoEquip (ptr); } void Actors::adjustMagicEffects (const MWWorld::Ptr& creature) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 9a44a99791..c147113fc6 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,108 +43,8 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - - // Beast races cannot equip shoes / boots, or full helms (head part vs hair part) - const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); - if(race->mData.mFlags & ESM::Race::Beast) - { - if(*slot == MWWorld::InventoryStore::Slot_Helmet) - { - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - - bool allow = true; - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_Head) - { - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - allow = false; - break; - } - } - - if(!allow) - break; - } - - if (*slot == MWWorld::InventoryStore::Slot_Boots) - { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) - { - if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - allow = false; - // Only notify the player, not npcs - if(actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - if(it.getType() == MWWorld::ContainerStore::Type_Clothing){ // It's shoes - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); - } - - else // It's boots - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - } - } - break; - } - } - - if(!allow) - break; - } - - } - - //Disable twohanded when shield equipped, shield when twohanded equipped - if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) - { - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - } - } - } - if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) - { - ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } - } - } + if(!MWWorld::Class::get(getTarget()).canEquip(actor,getTarget())) + break; // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2dfa241b3b..ee2072cf09 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,6 +259,11 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } + bool Class::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + { + return true; + } + void Class::adjustPosition(const MWWorld::Ptr& ptr) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index de4741e38b..4931da7a86 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,6 +242,9 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; + virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. Unequip twohanded item if neccesary + virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index dd518ff6a4..7a5ae38d0e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -128,8 +128,9 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) return mSlots[slot]; } -void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) +void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) { + const MWMechanics::NpcStats& stats = MWWorld::Class::get(npc).getNpcStats(npc); TSlots slots; initSlots (slots); @@ -183,6 +184,9 @@ void MWWorld::InventoryStore::autoEquip (const MWMechanics::NpcStats& stats) } } + if(!MWWorld::Class::get (test).canEquip (npc, test)) + continue; + if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { // unstack item pointed to by iterator if required diff --git a/apps/openmw/mwworld/inventorystore.hpp b/apps/openmw/mwworld/inventorystore.hpp index e55eca0ae7..cc28a0a0c0 100644 --- a/apps/openmw/mwworld/inventorystore.hpp +++ b/apps/openmw/mwworld/inventorystore.hpp @@ -78,7 +78,7 @@ namespace MWWorld ContainerStoreIterator getSlot (int slot); - void autoEquip (const MWMechanics::NpcStats& stats); + void autoEquip (const MWWorld::Ptr& npc); ///< Auto equip items according to stats and item value. const MWMechanics::MagicEffects& getMagicEffects(); From af2a38db3854ecae1c6cdf056ed80b93146fe036 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 08:27:26 -0700 Subject: [PATCH 0277/1537] Fix looping anims that dont have "loop start" --- apps/openmw/mwrender/animation.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fd575f9183..8dbd8d8073 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -307,7 +307,15 @@ void Animation::reset(const std::string &start, const std::string &stop) else { mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; + while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") + mNextKey++; + if(mNextKey != mCurrentKeys->end()) + mCurrentTime = mNextKey->first; + else + { + mNextKey = mCurrentKeys->begin(); + mCurrentTime = 0.0f; + } } if(stop.length() > 0) From 75b462b9744f1660af0374bc43c984e796008c24 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 5 Apr 2013 18:23:22 +0200 Subject: [PATCH 0278/1537] If alpha rejection was forced, we also need to force depth_write and depth_check --- components/nifogre/ogrenifloader.cpp | 1 + files/materials/objects.mat | 2 ++ 2 files changed, 3 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f8eca821ff..8f9d69f6e2 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -771,6 +771,7 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String { alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ alphaTest = result.second; + depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on } if((alphaFlags&1)) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 8740c82c34..49df4e3949 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -14,6 +14,7 @@ material openmw_objects_base is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default depth_write default + depth_check default alpha_rejection default transparent_sorting default @@ -38,6 +39,7 @@ material openmw_objects_base scene_blend $scene_blend alpha_rejection $alpha_rejection depth_write $depth_write + depth_check $depth_check transparent_sorting $transparent_sorting texture_unit diffuseMap From 0631b28646c5cfe12360be1356980db93e3ff050 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 10:13:54 -0700 Subject: [PATCH 0279/1537] Prepare for supporting controller objects --- apps/openmw/mwrender/animation.cpp | 7 +++++++ apps/openmw/mwrender/animation.hpp | 20 ++++++++++++++++++++ apps/openmw/mwrender/npcanimation.cpp | 1 + components/nifogre/ogrenifloader.hpp | 2 ++ 4 files changed, 30 insertions(+) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8dbd8d8073..00196c9d47 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -45,6 +45,7 @@ Animation::~Animation() for(size_t i = 0;i < mEntityList.mEntities.size();i++) sceneMgr->destroyEntity(mEntityList.mEntities[i]); } + mEntityList.mControllers.clear(); mEntityList.mParticles.clear(); mEntityList.mEntities.clear(); mEntityList.mSkelBase = NULL; @@ -129,6 +130,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); + for(size_t i = 0;i < mEntityList.mControllers.size();i++) + mEntityList.mControllers[i].setSource(ctrlval); } @@ -457,6 +462,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } + for(size_t i = 0;i < mEntityList.mControllers.size();i++) + mEntityList.mControllers[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7caf351694..3e7dee6db2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -16,6 +16,26 @@ namespace MWRender class Animation { protected: + class AnimationValue : public Ogre::ControllerValue + { + private: + Animation *mAnimation; + + public: + AnimationValue(Animation *anim) : mAnimation(anim) + { } + + virtual Ogre::Real getValue() const + { + return mAnimation->mCurrentTime; + } + + virtual void setValue(Ogre::Real value) + { + mAnimation->mCurrentTime = value; + } + }; + MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index f1af6a7d3c..b7bcad5995 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -367,6 +367,7 @@ void NpcAnimation::removeEntities(NifOgre::EntityList &entities) sceneMgr->destroyParticleSystem(entities.mParticles[i]); for(size_t i = 0;i < entities.mEntities.size();i++) sceneMgr->destroyEntity(entities.mEntities[i]); + entities.mControllers.clear(); entities.mParticles.clear(); entities.mEntities.clear(); entities.mSkelBase = NULL; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e6672541bd..819b4d8806 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -45,6 +45,8 @@ struct EntityList { std::vector mParticles; + std::vector > mControllers; + EntityList() : mSkelBase(0) { } }; From aa9df818a52574984406733edb7c916c7183b1c6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 5 Apr 2013 10:38:27 -0700 Subject: [PATCH 0280/1537] Add support for NiVisController --- components/nifogre/ogrenifloader.cpp | 103 ++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index f663cdf145..443b207103 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -62,6 +62,83 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { + +// FIXME: Should not be here. +class VisController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::Bone *mTarget; + + // FIXME: We are not getting all objects here. Skinned meshes get + // attached to the object's root node, and won't be connected via a + // TagPoint. + static void setVisible(Ogre::Node *node, int vis) + { + Ogre::Node::ChildNodeIterator iter = node->getChildIterator(); + while(iter.hasMoreElements()) + { + node = iter.getNext(); + setVisible(node, vis); + + Ogre::TagPoint *tag = dynamic_cast(node); + if(tag != NULL) + { + Ogre::MovableObject *obj = tag->getChildObject(); + if(obj != NULL) + obj->setVisible(vis); + } + } + } + + public: + Value(Ogre::Bone *target) : mTarget(target) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + int vis = static_cast(value); + setVisible(mTarget, vis); + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + std::vector mData; + + public: + Function(const Nif::NiVisData *data) + : Ogre::ControllerFunction(false), + mData(data->mVis) + { } + + virtual Ogre::Real calculate(Ogre::Real value) + { + if(mData.size() == 0) + return 1.0f; + + if(mData[0].time >= value) + return mData[0].isSet; + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > value) + return mData[i-1].isSet; + } + return mData.back().isSet; + } + }; +}; + + // Helper class that computes the bounding box and of a mesh class BoundsFinder { @@ -330,7 +407,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro { if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1129,7 +1207,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); - emitter->setDirection(Ogre::Vector3::UNIT_Z); + emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); + emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); @@ -1270,6 +1349,26 @@ class NIFMeshLoader : Ogre::ManualResourceLoader e = e->extra; } + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(!target) target = node; + + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + Ogre::SharedPtr > srcval; /* Filled in later */ + Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); + Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden { const Nif::NiTriShape *shape = static_cast(node); From b1257620d90904571a49fb75ac2a2080051311ff Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 22:58:21 +0200 Subject: [PATCH 0281/1537] Some cleanup in build dependencies. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index db0a47d844..35fb3a598b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,16 @@ before_script: - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 - - cat CMakeCache.txt before_install: - git submodule update --init --recursive - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - - sudo apt-get remove -qq libogre-static-dev - - sudo apt-get install -qq libois-dev libopenal-dev libpng-dev libogre-static-dev libmpg123-dev libsndfile1-dev libblkid-dev libfreeimage-dev libboost-all-dev uuid-dev libqt4-opengl libqt4-dev libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev ffmpeg libbullet-dev libmygui-static-dev libgtest-dev google-mock zziplib-bin libcg libav-tools libois-dev libopenal-dev libxaw7-dev + - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev + - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrand-dev libfreeimage-dev libpng-dev + - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev + - sudo apt-get install -qq libcg nvidia-cg-dev + - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev + - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev script: "make -j`grep -c processor /proc/cpuinfo`" branches: only: From 07d5d26b4a2f724553feb8ecacc9fe58ed15d9d2 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:02:44 +0200 Subject: [PATCH 0282/1537] Corrected typo. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 35fb3a598b..b8ebe6275c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev - - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrand-dev libfreeimage-dev libpng-dev + - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libcg nvidia-cg-dev - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev From d999c0a91c692289b4a3aba805c72ae41e4adf15 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:18:10 +0200 Subject: [PATCH 0283/1537] Enabled addtional Ubuntu repositories. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b8ebe6275c..f383d82721 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,7 @@ before_script: - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive + - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse partner" - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev From fb4f50ce8f577081bfdc796c9f6cbc998debcec9 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:28:44 +0200 Subject: [PATCH 0284/1537] Removed 'partner' repository. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f383d82721..61d5fa551c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ before_script: - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 before_install: - git submodule update --init --recursive - - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse partner" + - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/deps - sudo apt-get update -qq - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev From a48d60b5e34ed1d6dcfe6396392ec40120bf5412 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:34:23 +0200 Subject: [PATCH 0285/1537] Changed packet name from nvidia-cg-dev to nvidia-cg-toolkit. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 61d5fa551c..c574572490 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ before_install: - sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock libzzip-dev - sudo apt-get install -qq libqt4-dev libxaw7-dev libxrandr-dev libfreeimage-dev libpng-dev - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - - sudo apt-get install -qq libcg nvidia-cg-dev + - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev script: "make -j`grep -c processor /proc/cpuinfo`" From 99ff89d668b8d51a3f6b46af35a94bc26ef1d256 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Fri, 5 Apr 2013 23:41:15 +0200 Subject: [PATCH 0286/1537] Lowered number of used CPUs for compilation. Enabled building of unit tests. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c574572490..ee26fd5c1b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ compiler: before_script: - mkdir build - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 before_install: - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" @@ -16,7 +16,7 @@ before_install: - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev -script: "make -j`grep -c processor /proc/cpuinfo`" +script: "make -j4" branches: only: - master From 6529919102bde1d126121a5669cbb802949162dc Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:01:44 +0200 Subject: [PATCH 0287/1537] Enabled building of Gtest libary. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee26fd5c1b..96ce6d7eb2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,6 @@ language: cpp compiler: - - gcc -before_script: - - mkdir build - - cd build - - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 + - gcc before_install: - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" @@ -15,7 +11,17 @@ before_install: - sudo apt-get install -qq libopenal-dev libmpg123-dev libsndfile1-dev - sudo apt-get install -qq libcg nvidia-cg-toolkit - sudo apt-get install -qq libavcodec-dev libavformat-dev libavdevice-dev libavutil-dev libswscale-dev libpostproc-dev - - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev + - sudo apt-get install -qq libois-dev libbullet-dev libogre-static-dev libmygui-static-dev + - sudo mkdir /usr/src/gtest/build + - cd /usr/src/gtest/build + - sudo cmake .. -DBUILD_SHARED_LIBS=1 + - sudo make -j4 + - sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so + - sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so +before_script: + - mkdir build + - cd build + - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 script: "make -j4" branches: only: From 977da3eeb80d09d3eccc0d0f7cd19308e2e71472 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:18:14 +0200 Subject: [PATCH 0288/1537] Change back directory to the one where OpenMW is downloaded. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 96ce6d7eb2..8df94ca488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: cpp compiler: - gcc before_install: + - pwd - git submodule update --init --recursive - echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - echo "yes" | sudo apt-add-repository ppa:openmw/deps @@ -19,6 +20,7 @@ before_install: - sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so - sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so before_script: + - cd - - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 From 86457ce488b233141091b04487d1ed5d89ac4338 Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 00:45:04 +0200 Subject: [PATCH 0289/1537] Enabled running of openmw test suite. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8df94ca488..9ed8b7526c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,10 @@ language: cpp compiler: - gcc +branches: + only: + - master + - travis_ci_test before_install: - pwd - git submodule update --init --recursive @@ -24,11 +28,10 @@ before_script: - mkdir build - cd build - cmake .. -DOGRE_STATIC=1 -DMYGUI_STATIC=1 -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -script: "make -j4" -branches: - only: - - master - - travis_ci_test +script: + - make -j4 +after_script: + - openmw_test_suite notifications: recipients: - lgromanowski+travis.ci@gmail.com From 05e7cfeb70c80ebb3fcaa0d9f984366e65988a7f Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 01:04:41 +0200 Subject: [PATCH 0290/1537] Corrected path to the openmw test suite. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9ed8b7526c..54fff44e2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ compiler: branches: only: - master + - next - travis_ci_test before_install: - pwd @@ -31,7 +32,7 @@ before_script: script: - make -j4 after_script: - - openmw_test_suite + - ./openmw_test_suite notifications: recipients: - lgromanowski+travis.ci@gmail.com From 9ac56ce60e2d03761be32a3e83e947cdfc9f1f4e Mon Sep 17 00:00:00 2001 From: Lukasz Gromanowski Date: Sat, 6 Apr 2013 01:24:38 +0200 Subject: [PATCH 0291/1537] Removed travis_ci_test branch from checked branches list. Signed-off-by: Lukasz Gromanowski --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 54fff44e2e..374b38ce08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ branches: only: - master - next - - travis_ci_test before_install: - pwd - git submodule update --init --recursive From 81615c1ae5ac4055ffbe8c6239ebdf6b8b7fb029 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:18:36 -0700 Subject: [PATCH 0292/1537] Add a custom GrowFade particle affector --- CMakeLists.txt | 1 + libs/openengine/ogre/particles.cpp | 146 +++++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 17 ++++ libs/openengine/ogre/renderer.cpp | 15 +++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 181 insertions(+) create mode 100644 libs/openengine/ogre/particles.cpp create mode 100644 libs/openengine/ogre/particles.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e1b8e32e5e..b6a1017906 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,6 +75,7 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp ${LIBDIR}/openengine/ogre/fader.cpp + ${LIBDIR}/openengine/ogre/particles.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ) set(OENGINE_GUI diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp new file mode 100644 index 0000000000..3453b7f3d7 --- /dev/null +++ b/libs/openengine/ogre/particles.cpp @@ -0,0 +1,146 @@ +#include "particles.hpp" + +#include +#include +#include +#include + +class GrowFadeAffector : public Ogre::ParticleAffector +{ +public: + /** Command object for grow_time (see Ogre::ParamCommand).*/ + class CmdGrowTime : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GrowFadeAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getGrowTime()); + } + void doSet(void *target, const Ogre::String &val) + { + GrowFadeAffector *self = static_cast(target); + self->setGrowTime(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for fade_time (see Ogre::ParamCommand).*/ + class CmdFadeTime : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GrowFadeAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getFadeTime()); + } + void doSet(void *target, const Ogre::String &val) + { + GrowFadeAffector *self = static_cast(target); + self->setFadeTime(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Default constructor. */ + GrowFadeAffector(Ogre::ParticleSystem *psys) : ParticleAffector(psys) + { + mGrowTime = 0.0f; + mFadeTime = 0.0f; + + mType = "GrowFade"; + + // Init parameters + if(createParamDictionary("GrowFadeAffector")) + { + Ogre::ParamDictionary *dict = getParamDictionary(); + + Ogre::String grow_title("grow_time"); + Ogre::String fade_title("fade_time"); + Ogre::String grow_descr("Time from begin to reach full size."); + Ogre::String fade_descr("Time from end to shrink."); + + dict->addParameter(Ogre::ParameterDef(grow_title, grow_descr, Ogre::PT_REAL), &msGrowCmd); + dict->addParameter(Ogre::ParameterDef(fade_title, fade_descr, Ogre::PT_REAL), &msFadeCmd); + } + } + + /** See Ogre::ParticleAffector. */ + void _initParticle(Ogre::Particle *particle) + { + const Ogre::Real life_time = particle->totalTimeToLive; + Ogre::Real particle_time = particle->timeToLive; + + Ogre::Real width = mParent->getDefaultWidth(); + Ogre::Real height = mParent->getDefaultHeight(); + if(life_time-particle_time < mGrowTime) + { + Ogre::Real scale = (life_time-particle_time) / mGrowTime; + width *= scale; + height *= scale; + } + if(particle_time < mFadeTime) + { + Ogre::Real scale = particle_time / mFadeTime; + width *= scale; + height *= scale; + } + particle->setDimensions(width, height); + } + + /** See Ogre::ParticleAffector. */ + void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + const Ogre::Real life_time = p->totalTimeToLive; + Ogre::Real particle_time = p->timeToLive; + + Ogre::Real width = mParent->getDefaultWidth(); + Ogre::Real height = mParent->getDefaultHeight(); + if(life_time-particle_time < mGrowTime) + { + Ogre::Real scale = (life_time-particle_time) / mGrowTime; + width *= scale; + height *= scale; + } + if(particle_time < mFadeTime) + { + Ogre::Real scale = particle_time / mFadeTime; + width *= scale; + height *= scale; + } + p->setDimensions(width, height); + } + } + + void setGrowTime(Ogre::Real time) + { + mGrowTime = time; + } + Ogre::Real getGrowTime() const + { return mGrowTime; } + + void setFadeTime(Ogre::Real time) + { + mFadeTime = time; + } + Ogre::Real getFadeTime() const + { return mFadeTime; } + + static CmdGrowTime msGrowCmd; + static CmdFadeTime msFadeCmd; + +protected: + Ogre::Real mGrowTime; + Ogre::Real mFadeTime; +}; +GrowFadeAffector::CmdGrowTime GrowFadeAffector::msGrowCmd; +GrowFadeAffector::CmdFadeTime GrowFadeAffector::msFadeCmd; + +Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleAffector *p = new GrowFadeAffector(psys); + mAffectors.push_back(p); + return p; +} diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp new file mode 100644 index 0000000000..d466bb0308 --- /dev/null +++ b/libs/openengine/ogre/particles.hpp @@ -0,0 +1,17 @@ +#ifndef OENGINE_OGRE_PARTICLES_H +#define OENGINE_OGRE_PARTICLES_H + +#include + +/** Factory class for GrowFadeAffector. */ +class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory +{ + /** See Ogre::ParticleAffectorFactory */ + Ogre::String getName() const + { return "GrowFade"; } + + /** See Ogre::ParticleAffectorFactory */ + Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); +}; + +#endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 05760ffa98..c9e91968f5 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,5 +1,6 @@ #include "renderer.hpp" #include "fader.hpp" +#include "particles.hpp" #include "OgreRoot.h" #include "OgreRenderWindow.h" @@ -8,6 +9,8 @@ #include "OgreTextureManager.h" #include "OgreTexture.h" #include "OgreHardwarePixelBuffer.h" +#include +#include "OgreParticleAffectorFactory.h" #include @@ -24,6 +27,7 @@ using namespace Ogre; using namespace OEngine::Render; + #if defined(__APPLE__) && !defined(__LP64__) CustomRoot::CustomRoot(const Ogre::String& pluginFileName, @@ -106,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ai; + for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) + OGRE_DELETE (*ai); + mAffectorFactories.clear(); + #ifdef ENABLE_PLUGIN_GL delete mGLPlugin; mGLPlugin = NULL; @@ -197,6 +206,12 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + Ogre::ParticleAffectorFactory *affector; + affector = OGRE_NEW GrowFadeAffectorFactory(); + Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); + mAffectorFactories.push_back(affector); + + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 251dc9c54d..ea46f5ae62 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleAffectorFactory; } namespace OEngine @@ -94,6 +95,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mAffectorFactories; bool logging; public: From b5017e054309cbd77517d6256fb6ca50b92bf9d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:19:05 -0700 Subject: [PATCH 0293/1537] Implement NiParticleGrowFade --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 443b207103..4a388bf553 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -1220,7 +1221,10 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { if(e->recType == Nif::RC_NiParticleGrowFade) { - // TODO: Implement + const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); + affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); + affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } else if(e->recType == Nif::RC_NiParticleColorModifier) { From 99b915e652c27bfe1bc0e53e2d5cec9d12796e75 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 00:54:53 -0700 Subject: [PATCH 0294/1537] Fix some material warnings --- components/nifogre/ogrenifloader.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 54d2c8cf16..215462bac5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -712,7 +712,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, continue; if(texprop->textures[i].texture.empty()) { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name+"\n"); + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); continue; } @@ -840,10 +840,14 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); } - for(int i = 1;i < 7;i++) + for(int i = 0;i < 7;i++) { + if(i == Nif::NiTexturingProperty::BaseTexture || + i == Nif::NiTexturingProperty::BumpTexture || + i == Nif::NiTexturingProperty::GlowTexture) + continue; if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); } if (vertexColour) From 1d934e3112423306ac3ae58ffb30412e88274b24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 04:46:28 -0700 Subject: [PATCH 0295/1537] Reduce some stdout spam --- apps/openmw/mwmechanics/aiwander.cpp | 2 +- apps/openmw/mwscript/aiextensions.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e9db6d212a..3cd78a9338 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -13,7 +13,7 @@ MWMechanics::AiPackage * MWMechanics::AiWander::clone() const bool MWMechanics::AiWander::execute (const MWWorld::Ptr& actor) { - std::cout << "AiWadner completed.\n"; + // Return completed return true; } diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 8402a5b4cd..1ff6fbbf1f 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -196,8 +196,6 @@ namespace MWScript MWMechanics::AiWander wanderPackage(range, duration, time, idleList); MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSequence().stack(wanderPackage); - - std::cout << "AiWander" << std::endl; } }; From 41ce5464c9088e8c79a6c91fdbb741cec1e51bb9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 05:00:19 -0700 Subject: [PATCH 0296/1537] Recognize NiBSAnimationNode as a record type And don't warn about animated nodes without textkeys --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 11 ++++------- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index bf05e7576a..f97c506806 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -209,7 +209,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, { "NiBSParticleNode", &construct , RC_NiNode }, - { "NiBSAnimationNode", &construct , RC_NiNode }, + { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, { "NiRotatingParticles", &construct , RC_NiRotatingParticles }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 3a3cd9b84a..361af3f64c 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -59,6 +59,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, RC_NiVertWeightsExtraData, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 215462bac5..377fa94188 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -464,6 +464,10 @@ void loadResource(Ogre::Resource *resource) return; } + /* Animations without textkeys don't get Ogre::Animation objects. */ + if(!animroot) + return; + std::vector targets; // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file if(ctrls.size() == 0) // No animations? Then we're done. @@ -486,13 +490,6 @@ void loadResource(Ogre::Resource *resource) return; } - if(!animroot) - { - warn(Ogre::StringConverter::toString(ctrls.size())+" animated node(s) in "+ - skel->getName()+", but no text keys."); - return; - } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); From f764f243d2e42ac5e63a9f44e49deee641a69226 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 06:44:34 -0700 Subject: [PATCH 0297/1537] Fix the particle quota --- components/nif/data.hpp | 4 +++- components/nifogre/ogrenifloader.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index c13495ff8b..0804b53ae2 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -165,6 +165,8 @@ public: class NiAutoNormalParticlesData : public ShapeData { public: + int numParticles; + float particleSize; int activeCount; @@ -176,7 +178,7 @@ public: ShapeData::read(nif); // Should always match the number of vertices - nif->getUShort(); + numParticles = nif->getUShort(); particleSize = nif->getFloat(); activeCount = nif->getUShort(); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 377fa94188..cadedbd709 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1274,7 +1274,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->activeCount); + partsys->setParticleQuota(particledata->numParticles); Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) From 95730cc127149317583a6051df4eea7b331f3628 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 06:53:08 -0700 Subject: [PATCH 0298/1537] Create entities and particle systems for hidden objects They're set as (in)visible as appropriate. --- components/nifogre/ogrenifloader.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index cadedbd709..3f20fbab30 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1375,7 +1375,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader ctrl = ctrl->next; } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x01)) // Not hidden + if(node->recType == Nif::RC_NiTriShape) { const Nif::NiTriShape *shape = static_cast(node); @@ -1396,10 +1396,12 @@ class NIFMeshLoader : Ogre::ManualResourceLoader mesh->setAutoBuildEdgeLists(false); } - entities.mEntities.push_back(sceneMgr->createEntity(mesh)); + Ogre::Entity *entity = sceneMgr->createEntity(mesh); + entity->setVisible(!(flags&0x01)); + + entities.mEntities.push_back(entity); if(entities.mSkelBase) { - Ogre::Entity *entity = entities.mEntities.back(); if(entity->hasSkeleton()) entity->shareSkeletonInstanceWith(entities.mSkelBase); else @@ -1407,12 +1409,15 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - if((node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x01)) + if(node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) { Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); if(partsys != NULL) + { + partsys->setVisible(!(flags&0x01)); entities.mParticles.push_back(partsys); + } } const Nif::NiNode *ninode = dynamic_cast(node); From e0da2659729727481f7984983dc59551a27b076d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 08:15:12 -0700 Subject: [PATCH 0299/1537] Use accurate bone lookups for attaching objects NIFs don't requires nodes to have unique names, which means looking up a bone by name may get the wrong one. Instead, use a NifIndex:BoneHandle map to make sure we can get the proper bone from a given Nif::Node. --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3f20fbab30..06296ddeec 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -380,7 +380,6 @@ static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) return textkeys; } - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) { Ogre::Bone *bone; @@ -389,6 +388,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro else bone = skel->createBone(); if(parent) parent->addChild(bone); + mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); bone->setOrientation(node->trafo.rotation); bone->setPosition(node->trafo.pos); @@ -439,6 +439,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro } } +// Lookup to retrieve an Ogre bone handle for a given Nif record index +std::map mNifToOgreHandleMap; typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -569,6 +571,20 @@ static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::stri return skelMgr.create(name, group, true, &sLoaders[name]); } +// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be +// used when the bone name is insufficient as this is a relatively slow lookup +static int lookupOgreBoneHandle(const std::string &nifname, int idx) +{ + LoaderMap::const_iterator loader = sLoaders.find(nifname); + if(loader != sLoaders.end()) + { + std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); + if(entry != loader->second.mNifToOgreHandleMap.end()) + return entry->second; + } + throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); +} + }; NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; @@ -1285,7 +1301,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader createParticleEmitterAffectors(partsys, partctrl); if(!partctrl->emitter.empty() && !partsys->isAttached()) - entitybase->attachObjectToBone(partctrl->emitter->name, partsys); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); + entitybase->attachObjectToBone(trgtbone->getName(), partsys); + } } ctrl = ctrl->next; } @@ -1362,10 +1382,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - const Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(!target) target = node; - - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(target->name); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::SharedPtr > srcval; /* Filled in later */ Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); @@ -1405,7 +1423,11 @@ class NIFMeshLoader : Ogre::ManualResourceLoader if(entity->hasSkeleton()) entity->shareSkeletonInstanceWith(entities.mSkelBase); else - entities.mSkelBase->attachObjectToBone(shape->name, entity); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); + Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); + entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } } } From 0fb583e0659847a55d198cc5ecd07594bbc7768d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 17:35:36 +0200 Subject: [PATCH 0300/1537] added verifier for race record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/racecheck.cpp | 47 +++++++++++++++++++++++++++ apps/opencs/model/tools/racecheck.hpp | 29 +++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/racecheck.cpp create mode 100644 apps/opencs/model/tools/racecheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 07766507f7..0cf72b24c8 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck ) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp new file mode 100644 index 0000000000..50bb08a7c6 --- /dev/null +++ b/apps/opencs/model/tools/racecheck.cpp @@ -0,0 +1,47 @@ + +#include "racecheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) +: mRaces (races) +{} + +int CSMTools::RaceCheckStage::setup() +{ + return mRaces.getSize(); +} + +void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Race& race = mRaces.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Race, race.mId); + + // test for empty name and description + if (race.mName.empty()) + messages.push_back (id.toString() + "|" + race.mId + " has an empty name"); + + if (race.mDescription.empty()) + messages.push_back (id.toString() + "|" + race.mId + " has an empty description"); + + // test for positive height + if (race.mData.mHeight.mMale<=0) + messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height"); + + if (race.mData.mHeight.mFemale<=0) + messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height"); + + // test for non-negative weight + if (race.mData.mWeight.mMale<0) + messages.push_back (id.toString() + "|male " + race.mId + " has negative weight"); + + if (race.mData.mWeight.mFemale<0) + messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp new file mode 100644 index 0000000000..e3f12599ba --- /dev/null +++ b/apps/opencs/model/tools/racecheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_RACECHECK_H +#define CSM_TOOLS_RACECHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that race records are internally consistent + class RaceCheckStage : public Stage + { + const CSMWorld::IdCollection& mRaces; + + public: + + RaceCheckStage (const CSMWorld::IdCollection& races); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index db45de43e5..5fb37514f0 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -15,6 +15,7 @@ #include "skillcheck.hpp" #include "classcheck.hpp" #include "factioncheck.hpp" +#include "racecheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -60,6 +61,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new ClassCheckStage (mData.getClasses())); mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); + + mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); } return mVerifier; From 59f1d4b0476579146f358b827d4ca060f4b0a76f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:44:10 -0700 Subject: [PATCH 0301/1537] Add support for NiUVController on meshes --- apps/openmw/mwrender/animation.cpp | 5 +- components/nifogre/ogrenifloader.cpp | 120 ++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 00196c9d47..2b980320da 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -133,7 +133,10 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].setSource(ctrlval); + { + if(mEntityList.mControllers[i].getSource().isNull()) + mEntityList.mControllers[i].setSource(ctrlval); + } } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 06296ddeec..1e42fed37f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,105 @@ public: }; }; +class UVController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::MaterialPtr mMaterial; + Nif::FloatKeyList mUTrans; + Nif::FloatKeyList mVTrans; + Nif::FloatKeyList mUScale; + Nif::FloatKeyList mVScale; + + static float lookupValue(float time, const Nif::FloatKeyList &keys) + { + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + for(;iter != keys.mKeys.end();iter++) + { + if(iter->mTime > time) + continue; + Nif::FloatKeyList::VecType::const_iterator next(iter+1); + if(next == keys.mKeys.end()) + return iter->mValue; + float a = (time-iter->mTime) / (next->mTime-iter->mTime); + return iter->mValue + ((next->mValue - iter->mValue)*a); + } + return 0.0f; + } + + public: + Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + : mMaterial(material) + , mUTrans(data->mKeyList[0]) + , mVTrans(data->mKeyList[1]) + , mUScale(data->mKeyList[2]) + , mVScale(data->mKeyList[3]) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 1.0f; + } + + virtual void setValue(Ogre::Real value) + { + float uTrans = lookupValue(value, mUTrans); + float vTrans = lookupValue(value, mVTrans); + float uScale = lookupValue(value, mUScale); + float vScale = lookupValue(value, mVScale); + if(uScale == 0.0f) uScale = 1.0f; + if(vScale == 0.0f) vScale = 1.0f; + + Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); + while(techs.hasMoreElements()) + { + Ogre::Technique *tech = techs.getNext(); + Ogre::Technique::PassIterator passes = tech->getPassIterator(); + while(passes.hasMoreElements()) + { + Ogre::Pass *pass = passes.getNext(); + Ogre::TextureUnitState *tex = pass->getTextureUnitState(0); + tex->setTextureScroll(uTrans, vTrans); + tex->setTextureScale(uScale, vScale); + } + } + } + }; + + class Function : public Ogre::ControllerFunction + { + private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + + public: + Function(const Nif::NiUVController *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value; + mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + }; +}; + // Helper class that computes the bounding box and of a mesh class BoundsFinder @@ -409,7 +509,8 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(ctrl->recType == Nif::RC_NiKeyframeController) ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; @@ -1429,6 +1530,23 @@ class NIFMeshLoader : Ogre::ManualResourceLoader entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + + entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } } if(node->recType == Nif::RC_NiAutoNormalParticles || From e50b6b1cfe9f3738909e8857b8f67bb7b282ddd4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 09:45:26 -0700 Subject: [PATCH 0302/1537] Apply texture matrix 0 in the object shader --- files/materials/objects.shader | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d0e8173733..4868cf98d1 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -36,6 +36,8 @@ SH_BEGIN_PROGRAM shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix) + shUniform(float4x4, textureMatrix0) @shAutoConstant(textureMatrix0, texture_matrix, 0) + #if (VIEWPROJ_FIX) || (SHADOWS) shUniform(float4x4, worldMatrix) @shAutoConstant(worldMatrix, world_matrix) #endif @@ -118,7 +120,7 @@ { shOutputPosition = shMatrixMult(wvp, shInputPosition); - UV.xy = uv0; + UV.xy = shMatrixMult (textureMatrix0, float4(uv0,0,1)).xy; #if SECOND_UV_SET UV.zw = uv1; #endif From ebcb4c66c3adc94217bb912f48789ccde6682668 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 10:17:09 -0700 Subject: [PATCH 0303/1537] Properly read and use the NIF root record list --- components/nif/niffile.cpp | 18 +++++++++++------- components/nif/niffile.hpp | 14 +++++++++++++- components/nifbullet/bulletnifloader.cpp | 11 +++++------ components/nifogre/ogrenifloader.cpp | 20 ++++++++++---------- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index f97c506806..44eae2953d 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -345,14 +345,18 @@ void NIFFile::parse() } } - /* After the data, the nif contains an int N and then a list of N - ints following it. This might be a list of the root nodes in the - tree, but for the moment we ignore it. - */ + size_t rootNum = nif.getUInt(); + roots.resize(rootNum); - // Once parsing is done, do post-processing. - for(size_t i=0; ipost(this); + for(size_t i = 0;i < rootNum;i++) + { + intptr_t idx = nif.getInt(); + roots[i] = ((idx >= 0) ? records.at(idx) : NULL); + } + + // Once parsing is done, do post-processing. + for(size_t i=0; ipost(this); } /// \todo move to the write cpp file diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index ed11bdd7cb..6e629772e6 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -66,6 +66,9 @@ class NIFFile /// Record list std::vector records; + /// Root list + std::vector roots; + /// Parse the file void parse(); @@ -115,9 +118,18 @@ public: assert(res != NULL); return res; } - /// Number of records size_t numRecords() { return records.size(); } + + /// Get a given root + Record *getRoot(size_t index=0) + { + Record *res = roots.at(index); + assert(res != NULL); + return res; + } + /// Number of roots + size_t numRoots() { return roots.size(); } }; diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 08625ee9cb..6bd43f6e35 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -91,21 +91,20 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) // likely a sign of incomplete code rather than faulty input. Nif::NIFFile::ptr pnif (Nif::NIFFile::create (resourceName.substr(0, resourceName.length()-7))); Nif::NIFFile & nif = *pnif.get (); - if (nif.numRecords() < 1) + if (nif.numRoots() < 1) { - warn("Found no records in NIF."); + warn("Found no root nodes in NIF."); return; } - // The first record is assumed to be the root node - Nif::Record *r = nif.getRecord(0); + Nif::Record *r = nif.getRoot(0); assert(r != NULL); Nif::Node *node = dynamic_cast(r); if (node == NULL) { - warn("First record in file was not a node, but a " + - r->recName + ". Skipping file."); + warn("First root in file was not a node, but a " + + r->recName + ". Skipping file."); return; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1e42fed37f..830e85cdef 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -553,7 +553,7 @@ void loadResource(Ogre::Resource *resource) OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); - const Nif::Node *node = static_cast(nif->getRecord(0)); + const Nif::Node *node = static_cast(nif->getRoot(0)); std::vector ctrls; Ogre::Bone *animroot = NULL; @@ -1441,7 +1441,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader return; } - const Nif::Node *node = dynamic_cast(nif->getRecord(0)); + const Nif::Node *node = dynamic_cast(nif->getRecord(mShapeIndex)); findTriShape(mesh, node); } @@ -1603,21 +1603,21 @@ public: { Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); - if(nif.numRecords() < 1) + if(nif.numRoots() < 1) { - nif.warn("Found no NIF records in "+name+"."); + nif.warn("Found no root nodes in "+name+"."); return; } // The first record is assumed to be the root node - const Nif::Record *r = nif.getRecord(0); + const Nif::Record *r = nif.getRoot(0); assert(r != NULL); const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); + nif.warn("First root in "+name+" was not a node, but a "+ + r->recName+"."); return; } @@ -1722,14 +1722,14 @@ Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group return skel; Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); - if(nif->numRecords() < 1) + if(nif->numRoots() < 1) { - nif->warn("Found no NIF records in "+name+"."); + nif->warn("Found no root nodes in "+name+"."); return skel; } // The first record is assumed to be the root node - const Nif::Record *r = nif->getRecord(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); const Nif::Node *node = dynamic_cast(r); From 9bc3945f406f3cd252d3a05cf00dc175c7fea17e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 19:20:46 +0200 Subject: [PATCH 0304/1537] multiple fixes to UniversalId constructor --- apps/opencs/model/world/universalid.cpp | 69 ++++++++++++------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 2e5e6a0a0a..5c7547d71d 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -55,44 +55,41 @@ CSMWorld::UniversalId::UniversalId (const std::string& universalId) { std::string type = universalId.substr (0, index); - if (index==std::string::npos) - { - for (int i=0; sNoArg[i].mName; ++i) - if (type==sNoArg[i].mName) - { - mArgumentType = ArgumentType_None; - mType = sNoArg[i].mType; - mClass = sNoArg[i].mClass; + for (int i=0; sIdArg[i].mName; ++i) + if (type==sIdArg[i].mName) + { + mArgumentType = ArgumentType_Id; + mType = sIdArg[i].mType; + mClass = sIdArg[i].mClass; + mId = universalId.substr (index+2); + return; + } + + for (int i=0; sIndexArg[i].mName; ++i) + if (type==sIndexArg[i].mName) + { + mArgumentType = ArgumentType_Index; + mType = sIndexArg[i].mType; + mClass = sIndexArg[i].mClass; + + std::istringstream stream (universalId.substr (index+2)); + + if (stream >> mIndex) return; - } - } - else - { - for (int i=0; sIdArg[i].mName; ++i) - if (type==sIdArg[i].mName) - { - mArgumentType = ArgumentType_Id; - mType = sIdArg[i].mType; - mClass = sIdArg[i].mClass; - mId = universalId.substr (0, index); - return; - } - for (int i=0; sIndexArg[i].mName; ++i) - if (type==sIndexArg[i].mName) - { - mArgumentType = ArgumentType_Index; - mType = sIndexArg[i].mType; - mClass = sIndexArg[i].mClass; - - std::istringstream stream (universalId.substr (0, index)); - - if (stream >> mIndex) - return; - - break; - } - } + break; + } + } + else + { + for (int i=0; sNoArg[i].mName; ++i) + if (universalId==sNoArg[i].mName) + { + mArgumentType = ArgumentType_None; + mType = sNoArg[i].mType; + mClass = sNoArg[i].mClass; + return; + } } throw std::runtime_error ("invalid UniversalId: " + universalId); From 98e7b3fd938edbe334de7bfc36aa2d721f6a3b50 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 19:20:59 +0200 Subject: [PATCH 0305/1537] check for at least one playable race --- apps/opencs/model/tools/racecheck.cpp | 41 ++++++++++++++++++++------- apps/opencs/model/tools/racecheck.hpp | 5 ++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/tools/racecheck.cpp b/apps/opencs/model/tools/racecheck.cpp index 50bb08a7c6..1e7a4cab45 100644 --- a/apps/opencs/model/tools/racecheck.cpp +++ b/apps/opencs/model/tools/racecheck.cpp @@ -7,16 +7,7 @@ #include "../world/universalid.hpp" -CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) -: mRaces (races) -{} - -int CSMTools::RaceCheckStage::setup() -{ - return mRaces.getSize(); -} - -void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector& messages) { const ESM::Race& race = mRaces.getRecord (stage).get(); @@ -43,5 +34,35 @@ void CSMTools::RaceCheckStage::perform (int stage, std::vector& mes if (race.mData.mWeight.mFemale<0) messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); + // remember playable flag + if (race.mData.mFlags & 0x1) + mPlayable = true; + /// \todo check data members that can't be edited in the table view +} + +void CSMTools::RaceCheckStage::performFinal (std::vector& messages) +{ + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); + + if (!mPlayable) + messages.push_back (id.toString() + "|No playable race"); +} + +CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection& races) +: mRaces (races), mPlayable (false) +{} + +int CSMTools::RaceCheckStage::setup() +{ + mPlayable = false; + return mRaces.getSize()+1; +} + +void CSMTools::RaceCheckStage::perform (int stage, std::vector& messages) +{ + if (stage==mRaces.getSize()) + performFinal (messages); + else + performPerRecord (stage, messages); } \ No newline at end of file diff --git a/apps/opencs/model/tools/racecheck.hpp b/apps/opencs/model/tools/racecheck.hpp index e3f12599ba..155f799021 100644 --- a/apps/opencs/model/tools/racecheck.hpp +++ b/apps/opencs/model/tools/racecheck.hpp @@ -13,6 +13,11 @@ namespace CSMTools class RaceCheckStage : public Stage { const CSMWorld::IdCollection& mRaces; + bool mPlayable; + + void performPerRecord (int stage, std::vector& messages); + + void performFinal (std::vector& messages); public: From 1f3df4df0f9ccbdb452ea7e88de4b7f02c417a59 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Apr 2013 19:25:29 +0200 Subject: [PATCH 0306/1537] Perform a sanity check on count arguments --- apps/openmw/mwscript/miscextensions.cpp | 7 +++++++ apps/openmw/mwscript/transformationextensions.cpp | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index f329e30d90..489f6bd3db 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -399,6 +399,13 @@ namespace MWScript Interpreter::Type_Integer amount = runtime[0].mInteger; runtime.pop(); + if (amount<0) + throw std::runtime_error ("amount must be non-negative"); + + // no-op + if (amount == 0) + return; + MWWorld::ContainerStore& store = MWWorld::Class::get (ptr).getContainerStore (ptr); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 97dc6d7188..49688efb5d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -460,6 +460,13 @@ namespace MWScript Interpreter::Type_Integer direction = runtime[0].mInteger; runtime.pop(); + if (count<0) + throw std::runtime_error ("count must be non-negative"); + + // no-op + if (count == 0) + return; + ESM::Position ipos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); @@ -503,6 +510,13 @@ namespace MWScript Interpreter::Type_Integer direction = runtime[0].mInteger; runtime.pop(); + if (count<0) + throw std::runtime_error ("count must be non-negative"); + + // no-op + if (count == 0) + return; + ESM::Position ipos = me.getRefData().getPosition(); Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); Ogre::Quaternion rot(Ogre::Radian(-ipos.rot[2]), Ogre::Vector3::UNIT_Z); From c28399112637417ddf66a9b65ebec4409227d16e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 10:33:07 -0700 Subject: [PATCH 0307/1537] Remove an unneeded method --- components/nifogre/ogrenifloader.cpp | 30 +++------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 830e85cdef..5206ef8344 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1070,7 +1070,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } // Convert NiTriShape to Ogre::SubMesh - void handleNiTriShape(Ogre::Mesh *mesh, Nif::NiTriShape const *shape) + void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); @@ -1295,30 +1295,6 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } } - bool findTriShape(Ogre::Mesh *mesh, const Nif::Node *node) - { - if(node->recType == Nif::RC_NiTriShape && mShapeIndex == node->recIndex) - { - handleNiTriShape(mesh, dynamic_cast(node)); - return true; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - if(findTriShape(mesh, children[i].getPtr())) - return true; - } - } - } - return false; - } - typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -1441,8 +1417,8 @@ class NIFMeshLoader : Ogre::ManualResourceLoader return; } - const Nif::Node *node = dynamic_cast(nif->getRecord(mShapeIndex)); - findTriShape(mesh, node); + const Nif::Record *record = nif->getRecord(mShapeIndex); + createSubMesh(mesh, dynamic_cast(record)); } void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) From 6b151be3f427ea361e03e9830236642b41721aac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 11:26:51 -0700 Subject: [PATCH 0308/1537] Create particle systems even when MRK was specified --- components/nifogre/ogrenifloader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 5206ef8344..6a7c3c6dbf 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1444,9 +1444,9 @@ class NIFMeshLoader : Ogre::ManualResourceLoader // affecting the entire subtree of this obj if(sd->string == "MRK") { - // Marker objects. These are only visible in the + // Marker objects. These meshes are only visible in the // editor. - return; + flags |= 0x80000000; } } e = e->extra; @@ -1470,7 +1470,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader ctrl = ctrl->next; } - if(node->recType == Nif::RC_NiTriShape) + if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { const Nif::NiTriShape *shape = static_cast(node); From 8bf569d58ab00c1ef804b802e3bec5bc358032f0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:21:10 +0200 Subject: [PATCH 0309/1537] added basic sound table --- apps/opencs/model/world/data.cpp | 15 +++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadsoun.cpp | 8 ++++++++ components/esm/loadsoun.hpp | 3 +++ 9 files changed, 49 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fb835b986a..b6fb437695 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -77,12 +77,16 @@ CSMWorld::Data::Data() mRaces.addColumn (new WeightHeightColumn (false, true)); mRaces.addColumn (new WeightHeightColumn (false, false)); + mSounds.addColumn (new StringIdColumn); + mSounds.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); + addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); } CSMWorld::Data::~Data() @@ -151,6 +155,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getRaces() return mRaces; } +const CSMWorld::IdCollection& CSMWorld::Data::getSounds() const +{ + return mSounds; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSounds() +{ + return mSounds; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -191,6 +205,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; + case ESM::REC_SOUN: mSounds.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 6b729728f5..320480e639 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -28,6 +29,7 @@ namespace CSMWorld IdCollection mClasses; IdCollection mFactions; IdCollection mRaces; + IdCollection mSounds; std::vector mModels; std::map mModelIndex; @@ -68,6 +70,10 @@ namespace CSMWorld IdCollection& getRaces(); + const IdCollection& getSounds() const; + + IdCollection& getSounds(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 5c7547d71d..7bdc15c8c7 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -23,6 +23,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Classes, "Classes" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -35,6 +36,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Class, "Class" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 2213e15f31..a21d67fcd8 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -45,7 +45,9 @@ namespace CSMWorld Type_Factions, Type_Faction, Type_Races, - Type_Race + Type_Race, + Type_Sounds, + Type_Sound }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index e12929cf2e..611690ca65 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -105,6 +105,10 @@ void CSVDoc::View::setupWorldMenu() QAction *races = new QAction (tr ("Races"), this); connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView())); world->addAction (races); + + QAction *sounds = new QAction (tr ("Sounds"), this); + connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); + world->addAction (sounds); } void CSVDoc::View::setupUi() @@ -280,6 +284,11 @@ void CSVDoc::View::addRacesSubView() addSubView (CSMWorld::UniversalId::Type_Races); } +void CSVDoc::View::addSoundsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Sounds); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4132d73b20..e8e716b706 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -123,6 +123,8 @@ namespace CSVDoc void addFactionsSubView(); void addRacesSubView(); + + void addSoundsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index d5ba273776..3ba950f879 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -20,6 +20,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Classes, CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, + CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 87a08d2d3a..75d4bc8de6 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -23,4 +23,12 @@ void Sound::save(ESMWriter &esm) esm.writeHNT("DATA", mData, 3); } + void Sound::blank() + { + mSound.clear(); + + mData.mVolume = 128; + mData.mMinRange = 0; + mData.mMaxRange = 256; + } } diff --git a/components/esm/loadsoun.hpp b/components/esm/loadsoun.hpp index 8f59f690a1..f8e38ac092 100644 --- a/components/esm/loadsoun.hpp +++ b/components/esm/loadsoun.hpp @@ -21,6 +21,9 @@ struct Sound void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From ca289a317c579c44b83132cf2bb5b471a8d5b979 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 12:26:58 -0700 Subject: [PATCH 0310/1537] Separate the UVController function out and make it generic Also fix a timing bug in it. --- components/nifogre/ogrenifloader.cpp | 60 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 6a7c3c6dbf..dfdec0bfa6 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -66,6 +66,36 @@ namespace NifOgre { // FIXME: Should not be here. +class DefaultFunction : public Ogre::ControllerFunction +{ +private: + float mFrequency; + float mPhase; + float mStartTime; + float mStopTime; + +public: + DefaultFunction(const Nif::Controller *ctrl) + : Ogre::ControllerFunction(false) + , mFrequency(ctrl->frequency) + , mPhase(ctrl->phase) + , mStartTime(ctrl->timeStart) + , mStopTime(ctrl->timeStop) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } + + virtual Ogre::Real calculate(Ogre::Real value) + { + mDeltaCount += value*mFrequency; + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } +}; + class VisController { public: @@ -208,35 +238,7 @@ public: } }; - class Function : public Ogre::ControllerFunction - { - private: - float mFrequency; - float mPhase; - float mStartTime; - float mStopTime; - - public: - Function(const Nif::NiUVController *ctrl) - : Ogre::ControllerFunction(false) - , mFrequency(ctrl->frequency) - , mPhase(ctrl->phase) - , mStartTime(ctrl->timeStart) - , mStopTime(ctrl->timeStop) - { - mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } - - virtual Ogre::Real calculate(Ogre::Real value) - { - mDeltaCount += value; - mDeltaCount = std::fmod(mDeltaCount+(value*mFrequency) - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; - } - }; + typedef DefaultFunction Function; }; From dd5940b395a5439aa08cd080a0afb3f585fd99ae Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:40:03 +0200 Subject: [PATCH 0311/1537] added sound parameter columns to sonud table --- apps/opencs/model/world/columns.hpp | 60 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 3 ++ 2 files changed, 63 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f65f212da1..0416287ba0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -506,6 +506,66 @@ namespace CSMWorld return true; } }; + + template + struct SoundParamColumn : public Column + { + enum Type + { + Type_Volume, + Type_MinRange, + Type_MaxRange + }; + + Type mType; + + SoundParamColumn (Type type) + : Column ( + type==Type_Volume ? "Volume" : (type==Type_MinRange ? "Min Range" : "Max Range"), + ColumnBase::Display_Integer), + mType (type) + {} + + virtual QVariant get (const Record& record) const + { + int value = 0; + + switch (mType) + { + case Type_Volume: value = record.get().mData.mVolume; break; + case Type_MinRange: value = record.get().mData.mMinRange; break; + case Type_MaxRange: value = record.get().mData.mMaxRange; break; + } + + return value; + } + + virtual void set (Record& record, const QVariant& data) + { + int value = data.toInt(); + + if (value<0) + value = 0; + else if (value>255) + value = 255; + + ESXRecordT record2 = record.get(); + + switch (mType) + { + case Type_Volume: record2.mData.mVolume = static_cast (value); break; + case Type_MinRange: record2.mData.mMinRange = static_cast (value); break; + case Type_MaxRange: record2.mData.mMaxRange = static_cast (value); break; + } + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b6fb437695..afa70cdc17 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -79,6 +79,9 @@ CSMWorld::Data::Data() mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); + mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 63cbf7ddeb3a00d89dc43850219bfa7e86dcbd6e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 6 Apr 2013 12:41:40 -0700 Subject: [PATCH 0312/1537] Specify a default return for failed lookups --- components/nifogre/ogrenifloader.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dfdec0bfa6..d89d0d30a5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -182,7 +182,7 @@ public: Nif::FloatKeyList mUScale; Nif::FloatKeyList mVScale; - static float lookupValue(float time, const Nif::FloatKeyList &keys) + static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) { Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); for(;iter != keys.mKeys.end();iter++) @@ -195,7 +195,7 @@ public: float a = (time-iter->mTime) / (next->mTime-iter->mTime); return iter->mValue + ((next->mValue - iter->mValue)*a); } - return 0.0f; + return def; } public: @@ -215,12 +215,10 @@ public: virtual void setValue(Ogre::Real value) { - float uTrans = lookupValue(value, mUTrans); - float vTrans = lookupValue(value, mVTrans); - float uScale = lookupValue(value, mUScale); - float vScale = lookupValue(value, mVScale); - if(uScale == 0.0f) uScale = 1.0f; - if(vScale == 0.0f) vScale = 1.0f; + float uTrans = lookupValue(mUTrans, value, 0.0f); + float vTrans = lookupValue(mVTrans, value, 0.0f); + float uScale = lookupValue(mUScale, value, 1.0f); + float vScale = lookupValue(mVScale, value, 1.0f); Ogre::Material::TechniqueIterator techs = mMaterial->getTechniqueIterator(); while(techs.hasMoreElements()) From 50b58b2ead2ae4b4db3ad9936f9a781592f55823 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:43:05 +0200 Subject: [PATCH 0313/1537] added sound file column to sound table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 0416287ba0..75dfe15c27 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -566,6 +566,31 @@ namespace CSMWorld return true; } }; + + template + struct SoundFileColumn : public Column + { + SoundFileColumn() : Column ("Sound File", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mSound.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mSound = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index afa70cdc17..69109bd743 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -82,6 +82,7 @@ CSMWorld::Data::Data() mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); + mSounds.addColumn (new SoundFileColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From e2c6458adb3509388c178f421d08b73787119619 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:48:52 +0200 Subject: [PATCH 0314/1537] added verifier for sound records --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/soundcheck.cpp | 29 ++++++++++++++++++++++++++ apps/opencs/model/tools/soundcheck.hpp | 29 ++++++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/soundcheck.cpp create mode 100644 apps/opencs/model/tools/soundcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 0cf72b24c8..ffd4c7f1ea 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck racecheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck ) diff --git a/apps/opencs/model/tools/soundcheck.cpp b/apps/opencs/model/tools/soundcheck.cpp new file mode 100644 index 0000000000..52834e6594 --- /dev/null +++ b/apps/opencs/model/tools/soundcheck.cpp @@ -0,0 +1,29 @@ + +#include "soundcheck.hpp" + +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SoundCheckStage::SoundCheckStage (const CSMWorld::IdCollection& sounds) +: mSounds (sounds) +{} + +int CSMTools::SoundCheckStage::setup() +{ + return mSounds.getSize(); +} + +void CSMTools::SoundCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Sound& sound = mSounds.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); + + if (sound.mData.mMinRange>sound.mData.mMaxRange) + messages.push_back (id.toString() + "|Maximum range larger than minimum range"); + + /// \todo check, if the sound file exists +} \ No newline at end of file diff --git a/apps/opencs/model/tools/soundcheck.hpp b/apps/opencs/model/tools/soundcheck.hpp new file mode 100644 index 0000000000..a309763a12 --- /dev/null +++ b/apps/opencs/model/tools/soundcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SOUNDCHECK_H +#define CSM_TOOLS_SOUNDCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that sound records are internally consistent + class SoundCheckStage : public Stage + { + const CSMWorld::IdCollection& mSounds; + + public: + + SoundCheckStage (const CSMWorld::IdCollection& sounds); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 5fb37514f0..4003bc8840 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -16,6 +16,7 @@ #include "classcheck.hpp" #include "factioncheck.hpp" #include "racecheck.hpp" +#include "soundcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -63,6 +64,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new FactionCheckStage (mData.getFactions())); mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); + + mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); } return mVerifier; From ec7a8f1add42914684290b4e99bbc8d8f054d586 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 6 Apr 2013 21:58:28 +0200 Subject: [PATCH 0315/1537] small fix --- components/esm/loadsoun.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp index 75d4bc8de6..07af2b5e91 100644 --- a/components/esm/loadsoun.cpp +++ b/components/esm/loadsoun.cpp @@ -29,6 +29,6 @@ void Sound::save(ESMWriter &esm) mData.mVolume = 128; mData.mMinRange = 0; - mData.mMaxRange = 256; + mData.mMaxRange = 255; } } From 4daaa4030d7434b50a2f835f44329a217e9be357 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 00:12:04 +0200 Subject: [PATCH 0316/1537] Added shader based MyGUI render manager to allow using Ogre's next generation render systems. --- files/CMakeLists.txt | 3 + files/materials/mygui.mat | 25 ++ files/materials/mygui.shader | 45 +++ files/materials/mygui.shaderset | 15 + libs/openengine/gui/manager.cpp | 537 +++++++++++++++++++++++++++++++- libs/openengine/gui/manager.hpp | 4 +- 6 files changed, 625 insertions(+), 4 deletions(-) create mode 100644 files/materials/mygui.mat create mode 100644 files/materials/mygui.shader create mode 100644 files/materials/mygui.shaderset diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9e65b516b7..9b2325744e 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -44,6 +44,9 @@ set(MATERIAL_FILES watersim_common.h watersim.mat watersim.shaderset + mygui.mat + mygui.shader + mygui.shaderset ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/mygui.mat b/files/materials/mygui.mat new file mode 100644 index 0000000000..78cba3f897 --- /dev/null +++ b/files/materials/mygui.mat @@ -0,0 +1,25 @@ +material MyGUI/NoTexture +{ + pass + { + vertex_program mygui_vertex + fragment_program mygui_fragment + shader_properties + { + has_texture false + } + } +} + +material MyGUI/OneTexture +{ + pass + { + vertex_program mygui_vertex + fragment_program mygui_fragment + shader_properties + { + has_texture true + } + } +} diff --git a/files/materials/mygui.shader b/files/materials/mygui.shader new file mode 100644 index 0000000000..014558d972 --- /dev/null +++ b/files/materials/mygui.shader @@ -0,0 +1,45 @@ +#include "core.h" + +#define TEXTURE @shPropertyBool(has_texture) + +#ifdef SH_VERTEX_SHADER + + SH_BEGIN_PROGRAM +#if TEXTURE + shVertexInput(float2, uv0) + shOutput(float2, UV) +#endif + shColourInput(float4) + shOutput(float4, colourPassthrough) + + SH_START_PROGRAM + { + shOutputPosition = float4(shInputPosition.xyz, 1.f); +#if TEXTURE + UV.xy = uv0; +#endif + colourPassthrough = colour; + } + +#else + + + SH_BEGIN_PROGRAM + +#if TEXTURE + shSampler2D(diffuseMap) + shInput(float2, UV) +#endif + + shInput(float4, colourPassthrough) + + SH_START_PROGRAM + { +#if TEXTURE + shOutputColour(0) = shSample(diffuseMap, UV.xy) * colourPassthrough; +#else + shOutputColour(0) = colourPassthrough; +#endif + } + +#endif diff --git a/files/materials/mygui.shaderset b/files/materials/mygui.shaderset new file mode 100644 index 0000000000..980cd4caf4 --- /dev/null +++ b/files/materials/mygui.shaderset @@ -0,0 +1,15 @@ +shader_set mygui_vertex +{ + source mygui.shader + type vertex + profiles_cg vs_2_0 vp40 arbvp1 + profiles_hlsl vs_3_0 vs_2_0 +} + +shader_set mygui_fragment +{ + source mygui.shader + type fragment + profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 + profiles_hlsl ps_3_0 ps_2_0 +} diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index c9b5614008..f9117586fe 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -2,11 +2,18 @@ #include #include +#include #include +#include +#include + using namespace OEngine::GUI; +namespace MyGUI +{ + /* * As of MyGUI 3.2.0, MyGUI::OgreDataManager::isDataExist is unnecessarily complex * this override fixes the resulting performance issue. @@ -20,6 +27,532 @@ public: } }; + +/* + * As of MyGUI 3.2.0, rendering with shaders is not supported. + * We definitely need this though to run in GL3 core / DX11 at all. + * To make matters worse, subclassing OgreRenderManager doesn't seem to be possible here. :/ + */ +class ShaderBasedRenderManager : public RenderManager, + public IRenderTarget, + public Ogre::WindowEventListener, + public Ogre::RenderQueueListener, + public Ogre::RenderSystem::Listener +{ + // флаг для обновления всех и вся + bool mUpdate; + + IntSize mViewSize; + + Ogre::SceneManager* mSceneManager; + + VertexColourType mVertexFormat; + + // окно, на которое мы подписываемся для изменения размеров + Ogre::RenderWindow* mWindow; + + // вьюпорт, с которым работает система + unsigned short mActiveViewport; + + Ogre::RenderSystem* mRenderSystem; + Ogre::TextureUnitState::UVWAddressingMode mTextureAddressMode; + Ogre::LayerBlendModeEx mColorBlendMode, mAlphaBlendMode; + + RenderTargetInfo mInfo; + + typedef std::map MapTexture; + MapTexture mTextures; + + bool mIsInitialise; + bool mManualRender; + size_t mCountBatch; + + // ADDED + Ogre::GpuProgram* mVertexProgramNoTexture; + Ogre::GpuProgram* mVertexProgramOneTexture; + Ogre::GpuProgram* mFragmentProgramNoTexture; + Ogre::GpuProgram* mFragmentProgramOneTexture; + +public: + ShaderBasedRenderManager& getInstance() + { + return *getInstancePtr(); + } + ShaderBasedRenderManager* getInstancePtr() + { + return static_cast(RenderManager::getInstancePtr()); + } + + ShaderBasedRenderManager() : + mUpdate(false), + mSceneManager(nullptr), + mWindow(nullptr), + mActiveViewport(0), + mRenderSystem(nullptr), + mIsInitialise(false), + mManualRender(false), + mCountBatch(0) + { + } + + void initialise(Ogre::RenderWindow* _window, Ogre::SceneManager* _scene) + { + MYGUI_PLATFORM_ASSERT(!mIsInitialise, getClassTypeName() << " initialised twice"); + MYGUI_PLATFORM_LOG(Info, "* Initialise: " << getClassTypeName()); + + mColorBlendMode.blendType = Ogre::LBT_COLOUR; + mColorBlendMode.source1 = Ogre::LBS_TEXTURE; + mColorBlendMode.source2 = Ogre::LBS_DIFFUSE; + mColorBlendMode.operation = Ogre::LBX_MODULATE; + + mAlphaBlendMode.blendType = Ogre::LBT_ALPHA; + mAlphaBlendMode.source1 = Ogre::LBS_TEXTURE; + mAlphaBlendMode.source2 = Ogre::LBS_DIFFUSE; + mAlphaBlendMode.operation = Ogre::LBX_MODULATE; + + mTextureAddressMode.u = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.v = Ogre::TextureUnitState::TAM_CLAMP; + mTextureAddressMode.w = Ogre::TextureUnitState::TAM_CLAMP; + + mSceneManager = nullptr; + mWindow = nullptr; + mUpdate = false; + mRenderSystem = nullptr; + mActiveViewport = 0; + + Ogre::Root* root = Ogre::Root::getSingletonPtr(); + if (root != nullptr) + setRenderSystem(root->getRenderSystem()); + setRenderWindow(_window); + setSceneManager(_scene); + + // ADDED + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); + mVertexProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getVertexProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); + mVertexProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getVertexProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/NoTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/NoTexture", "Default"); + mFragmentProgramNoTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getFragmentProgram()->_getBindingDelegate(); + + mat = sh::Factory::getInstance().getMaterialInstance("MyGUI/OneTexture"); + sh::Factory::getInstance()._ensureMaterial("MyGUI/OneTexture", "Default"); + mFragmentProgramOneTexture = static_cast(mat->getMaterial())->getOgreTechniqueForConfiguration("Default")->getPass(0) + ->getFragmentProgram()->_getBindingDelegate(); + + + + MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully initialized"); + mIsInitialise = true; + } + + void shutdown() + { + MYGUI_PLATFORM_ASSERT(mIsInitialise, getClassTypeName() << " is not initialised"); + MYGUI_PLATFORM_LOG(Info, "* Shutdown: " << getClassTypeName()); + + destroyAllResources(); + + setSceneManager(nullptr); + setRenderWindow(nullptr); + setRenderSystem(nullptr); + + MYGUI_PLATFORM_LOG(Info, getClassTypeName() << " successfully shutdown"); + mIsInitialise = false; + } + + void setRenderSystem(Ogre::RenderSystem* _render) + { + // отписываемся + if (mRenderSystem != nullptr) + { + mRenderSystem->removeListener(this); + mRenderSystem = nullptr; + } + + mRenderSystem = _render; + + // подписываемся на рендер евент + if (mRenderSystem != nullptr) + { + mRenderSystem->addListener(this); + + // формат цвета в вершинах + Ogre::VertexElementType vertex_type = mRenderSystem->getColourVertexElementType(); + if (vertex_type == Ogre::VET_COLOUR_ARGB) + mVertexFormat = VertexColourType::ColourARGB; + else if (vertex_type == Ogre::VET_COLOUR_ABGR) + mVertexFormat = VertexColourType::ColourABGR; + + updateRenderInfo(); + } + } + + Ogre::RenderSystem* getRenderSystem() + { + return mRenderSystem; + } + + void setRenderWindow(Ogre::RenderWindow* _window) + { + // отписываемся + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); + mWindow = nullptr; + } + + mWindow = _window; + + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); + windowResized(mWindow); + } + } + + void setSceneManager(Ogre::SceneManager* _scene) + { + if (nullptr != mSceneManager) + { + mSceneManager->removeRenderQueueListener(this); + mSceneManager = nullptr; + } + + mSceneManager = _scene; + + if (nullptr != mSceneManager) + { + mSceneManager->addRenderQueueListener(this); + } + } + + void setActiveViewport(unsigned short _num) + { + mActiveViewport = _num; + + if (mWindow != nullptr) + { + Ogre::WindowEventUtilities::removeWindowEventListener(mWindow, this); + Ogre::WindowEventUtilities::addWindowEventListener(mWindow, this); + + // рассылка обновлений + windowResized(mWindow); + } + } + + void renderQueueStarted(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& skipThisInvocation) + { + Gui* gui = Gui::getInstancePtr(); + if (gui == nullptr) + return; + + if (Ogre::RENDER_QUEUE_OVERLAY != queueGroupId) + return; + + Ogre::Viewport* viewport = mSceneManager->getCurrentViewport(); + if (nullptr == viewport + || !viewport->getOverlaysEnabled()) + return; + + if (mWindow->getNumViewports() <= mActiveViewport + || viewport != mWindow->getViewport(mActiveViewport)) + return; + + mCountBatch = 0; + + static Timer timer; + static unsigned long last_time = timer.getMilliseconds(); + unsigned long now_time = timer.getMilliseconds(); + unsigned long time = now_time - last_time; + + onFrameEvent((float)((double)(time) / (double)1000)); + + last_time = now_time; + + //begin(); + setManualRender(true); + onRenderToTarget(this, mUpdate); + //end(); + + // сбрасываем флаг + mUpdate = false; + } + + void renderQueueEnded(Ogre::uint8 queueGroupId, const Ogre::String& invocation, bool& repeatThisInvocation) + { + } + + void eventOccurred(const Ogre::String& eventName, const Ogre::NameValuePairList* parameters) + { + if (eventName == "DeviceLost") + { + } + else if (eventName == "DeviceRestored") + { + // обновить всех + mUpdate = true; + } + } + + IVertexBuffer* createVertexBuffer() + { + return new OgreVertexBuffer(); + } + + void destroyVertexBuffer(IVertexBuffer* _buffer) + { + delete _buffer; + } + + // для оповещений об изменении окна рендера + void windowResized(Ogre::RenderWindow* _window) + { + if (_window->getNumViewports() > mActiveViewport) + { + Ogre::Viewport* port = _window->getViewport(mActiveViewport); +#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 + Ogre::OrientationMode orient = port->getOrientationMode(); + if (orient == Ogre::OR_DEGREE_90 || orient == Ogre::OR_DEGREE_270) + mViewSize.set(port->getActualHeight(), port->getActualWidth()); + else + mViewSize.set(port->getActualWidth(), port->getActualHeight()); +#else + mViewSize.set(port->getActualWidth(), port->getActualHeight()); +#endif + + // обновить всех + mUpdate = true; + + updateRenderInfo(); + + onResizeView(mViewSize); + } + } + + void updateRenderInfo() + { + if (mRenderSystem != nullptr) + { + mInfo.maximumDepth = mRenderSystem->getMaximumDepthInputValue(); + mInfo.hOffset = mRenderSystem->getHorizontalTexelOffset() / float(mViewSize.width); + mInfo.vOffset = mRenderSystem->getVerticalTexelOffset() / float(mViewSize.height); + mInfo.aspectCoef = float(mViewSize.height) / float(mViewSize.width); + mInfo.pixScaleX = 1.0f / float(mViewSize.width); + mInfo.pixScaleY = 1.0f / float(mViewSize.height); + } + } + + void doRender(IVertexBuffer* _buffer, ITexture* _texture, size_t _count) + { + if (getManualRender()) + { + begin(); + setManualRender(false); + } + + // ADDED + + if (_texture) + { + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramOneTexture); + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramOneTexture); + } + else + { + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mVertexProgramNoTexture); + Ogre::Root::getSingleton().getRenderSystem()->bindGpuProgram(mFragmentProgramNoTexture); + } + + if (_texture) + { + OgreTexture* texture = static_cast(_texture); + Ogre::TexturePtr texture_ptr = texture->getOgreTexture(); + if (!texture_ptr.isNull()) + { + mRenderSystem->_setTexture(0, true, texture_ptr); + mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); + } + } + + OgreVertexBuffer* buffer = static_cast(_buffer); + Ogre::RenderOperation* operation = buffer->getRenderOperation(); + operation->vertexData->vertexCount = _count; + + mRenderSystem->_render(*operation); + + ++ mCountBatch; + } + + void begin() + { + // set-up matrices + mRenderSystem->_setWorldMatrix(Ogre::Matrix4::IDENTITY); + mRenderSystem->_setViewMatrix(Ogre::Matrix4::IDENTITY); + +#if OGRE_VERSION >= MYGUI_DEFINE_VERSION(1, 7, 0) && OGRE_NO_VIEWPORT_ORIENTATIONMODE == 0 + Ogre::OrientationMode orient = mWindow->getViewport(mActiveViewport)->getOrientationMode(); + mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY * Ogre::Quaternion(Ogre::Degree(orient * 90.f), Ogre::Vector3::UNIT_Z)); +#else + mRenderSystem->_setProjectionMatrix(Ogre::Matrix4::IDENTITY); +#endif + + // initialise render settings + mRenderSystem->setLightingEnabled(false); + mRenderSystem->_setDepthBufferParams(false, false); + mRenderSystem->_setDepthBias(0, 0); + mRenderSystem->_setCullingMode(Ogre::CULL_NONE); + mRenderSystem->_setFog(Ogre::FOG_NONE); + mRenderSystem->_setColourBufferWriteEnabled(true, true, true, true); + mRenderSystem->unbindGpuProgram(Ogre::GPT_FRAGMENT_PROGRAM); + mRenderSystem->unbindGpuProgram(Ogre::GPT_VERTEX_PROGRAM); + mRenderSystem->setShadingType(Ogre::SO_GOURAUD); + + // initialise texture settings + mRenderSystem->_setTextureCoordCalculation(0, Ogre::TEXCALC_NONE); + mRenderSystem->_setTextureCoordSet(0, 0); + mRenderSystem->_setTextureUnitFiltering(0, Ogre::FO_LINEAR, Ogre::FO_LINEAR, Ogre::FO_NONE); + mRenderSystem->_setTextureAddressingMode(0, mTextureAddressMode); + mRenderSystem->_setTextureMatrix(0, Ogre::Matrix4::IDENTITY); +#if OGRE_VERSION < MYGUI_DEFINE_VERSION(1, 6, 0) + mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0); +#else + mRenderSystem->_setAlphaRejectSettings(Ogre::CMPF_ALWAYS_PASS, 0, false); +#endif + mRenderSystem->_setTextureBlendMode(0, mColorBlendMode); + mRenderSystem->_setTextureBlendMode(0, mAlphaBlendMode); + mRenderSystem->_disableTextureUnitsFrom(1); + + // enable alpha blending + mRenderSystem->_setSceneBlending(Ogre::SBF_SOURCE_ALPHA, Ogre::SBF_ONE_MINUS_SOURCE_ALPHA); + + // always use wireframe + // TODO: add option to enable wireframe mode in platform + mRenderSystem->_setPolygonMode(Ogre::PM_SOLID); + } + + void end() + { + } + + ITexture* createTexture(const std::string& _name) + { + MapTexture::const_iterator item = mTextures.find(_name); + MYGUI_PLATFORM_ASSERT(item == mTextures.end(), "Texture '" << _name << "' already exist"); + + OgreTexture* texture = new OgreTexture(_name, OgreDataManager::getInstance().getGroup()); + mTextures[_name] = texture; + return texture; + } + + void destroyTexture(ITexture* _texture) + { + if (_texture == nullptr) return; + + MapTexture::iterator item = mTextures.find(_texture->getName()); + MYGUI_PLATFORM_ASSERT(item != mTextures.end(), "Texture '" << _texture->getName() << "' not found"); + + mTextures.erase(item); + delete _texture; + } + + ITexture* getTexture(const std::string& _name) + { + MapTexture::const_iterator item = mTextures.find(_name); + if (item == mTextures.end()) + { + Ogre::TexturePtr texture = (Ogre::TexturePtr)Ogre::TextureManager::getSingleton().getByName(_name); + if (!texture.isNull()) + { + ITexture* result = createTexture(_name); + static_cast(result)->setOgreTexture(texture); + return result; + } + return nullptr; + } + return item->second; + } + + bool isFormatSupported(PixelFormat _format, TextureUsage _usage) + { + return Ogre::TextureManager::getSingleton().isFormatSupported( + Ogre::TEX_TYPE_2D, + OgreTexture::convertFormat(_format), + OgreTexture::convertUsage(_usage)); + } + + void destroyAllResources() + { + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + delete item->second; + } + mTextures.clear(); + } + +#if MYGUI_DEBUG_MODE == 1 + bool checkTexture(ITexture* _texture) + { + for (MapTexture::const_iterator item = mTextures.begin(); item != mTextures.end(); ++item) + { + if (item->second == _texture) + return true; + } + return false; + } +#endif + + const IntSize& getViewSize() const + { + return mViewSize; + } + + VertexColourType getVertexFormat() + { + return mVertexFormat; + } + + const RenderTargetInfo& getInfo() + { + return mInfo; + } + + size_t getActiveViewport() + { + return mActiveViewport; + } + + Ogre::RenderWindow* getRenderWindow() + { + return mWindow; + } + + bool getManualRender() + { + return mManualRender; + } + + void setManualRender(bool _value) + { + mManualRender = _value; + } + + size_t getBatchCount() const + { + return mCountBatch; + } +}; + +} + + void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging, const std::string& logDir) { assert(wnd); @@ -41,8 +574,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new OgreRenderManager(); - mDataManager = new FixedOgreDataManager(); + mRenderManager = new MyGUI::ShaderBasedRenderManager(); + mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index 16673ef980..eec867ff8b 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,7 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; - class OgreRenderManager; + class ShaderBasedRenderManager; } namespace Ogre @@ -25,7 +25,7 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mRenderManager; Ogre::SceneManager* mSceneMgr; From d97b341dc6de0b640e55e14a5f467c5d75344b38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:02:21 -0700 Subject: [PATCH 0317/1537] Rename NIFMeshLoader to NIFObjectLoader --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d89d0d30a5..130e940208 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1012,11 +1012,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, std::map NIFMaterialLoader::MaterialMap; -/** Manual resource loader for NIF meshes. This is the main class - responsible for translating the internal NIF mesh structure into - something Ogre can use. +/** Manual resource loader for NIF objects (meshes, particle systems, etc). + * This is the main class responsible for translating the internal NIF + * structures into something Ogre can use. */ -class NIFMeshLoader : Ogre::ManualResourceLoader +class NIFObjectLoader : Ogre::ManualResourceLoader { std::string mName; std::string mGroup; @@ -1296,7 +1296,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - typedef std::map LoaderMap; + typedef std::map LoaderMap; static LoaderMap sLoaders; @@ -1399,7 +1399,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } - NIFMeshLoader(const std::string &name, const std::string &group) + NIFObjectLoader(const std::string &name, const std::string &group) : mName(name), mGroup(group), mShapeIndex(~(size_t)0) { } @@ -1421,13 +1421,13 @@ class NIFMeshLoader : Ogre::ManualResourceLoader createSubMesh(mesh, dynamic_cast(record)); } - void createEntities(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) + void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) { - // Do not create meshes for the collision shape (includes all children) + // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) return; - // Marker objects: just skip the entire node + // Marker objects: just skip the entire node branch /// \todo don't do this in the editor if (node->name.find("marker") != std::string::npos) return; @@ -1483,7 +1483,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { - NIFMeshLoader *loader = &sLoaders[fullname]; + NIFObjectLoader *loader = &sLoaders[fullname]; *loader = *this; loader->mShapeIndex = shape->recIndex; @@ -1543,7 +1543,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createEntities(sceneMgr, children[i].getPtr(), entities, flags); + createObjects(sceneMgr, children[i].getPtr(), entities, flags); } } } @@ -1561,7 +1561,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader Ogre::MeshPtr mesh = meshMgr.getByName(fullname); if(mesh.isNull()) { - NIFMeshLoader *loader = &sLoaders[fullname]; + NIFObjectLoader *loader = &sLoaders[fullname]; *loader = *this; mesh = meshMgr.createManual(fullname, mGroup, loader); @@ -1572,7 +1572,7 @@ class NIFMeshLoader : Ogre::ManualResourceLoader } public: - NIFMeshLoader() : mShapeIndex(~(size_t)0) + NIFObjectLoader() : mShapeIndex(~(size_t)0) { } static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) @@ -1601,13 +1601,13 @@ public: if(!hasSkel) hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - NIFMeshLoader meshldr(name, group); + NIFObjectLoader meshldr(name, group); if(hasSkel) meshldr.createSkelBase(sceneMgr, node, entities); - meshldr.createEntities(sceneMgr, node, entities); + meshldr.createObjects(sceneMgr, node, entities); } }; -NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; +NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) @@ -1615,7 +1615,7 @@ EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, EntityList entitylist; Misc::StringUtils::toLower(name); - NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); for(size_t i = 0;i < entitylist.mEntities.size();i++) { @@ -1634,7 +1634,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen EntityList entitylist; Misc::StringUtils::toLower(name); - NIFMeshLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); bool isskinned = false; for(size_t i = 0;i < entitylist.mEntities.size();i++) From 834a6a1f009c2741465a99605f0b1a06661b0c58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:14:26 -0700 Subject: [PATCH 0318/1537] Remove old, unused code --- components/nifogre/ogrenifloader.cpp | 44 +--------------------------- 1 file changed, 1 insertion(+), 43 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 130e940208..99c6a65dcf 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1719,46 +1719,4 @@ Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group return NIFSkeletonLoader::createSkeleton(name, group, node); } - -/* More code currently not in use, from the old D source. This was - used in the first attempt at loading NIF meshes, where each submesh - in the file was given a separate bone in a skeleton. Unfortunately - the OGRE skeletons can't hold more than 256 bones, and some NIFs go - way beyond that. The code might be of use if we implement animated - submeshes like this (the part of the NIF that is animated is - usually much less than the entire file, but the method might still - not be water tight.) - -// Insert a raw RGBA image into the texture system. -extern "C" void ogre_insertTexture(char* name, uint32_t width, uint32_t height, void *data) -{ - TexturePtr texture = TextureManager::getSingleton().createManual( - name, // name - "General", // group - TEX_TYPE_2D, // type - width, height, // width & height - 0, // number of mipmaps - PF_BYTE_RGBA, // pixel format - TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for - // textures updated very often (e.g. each frame) - - // Get the pixel buffer - HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); - - // Lock the pixel buffer and get a pixel box - pixelBuffer->lock(HardwareBuffer::HBL_NORMAL); // for best performance use HBL_DISCARD! - const PixelBox& pixelBox = pixelBuffer->getCurrentLock(); - - void *dest = pixelBox.data; - - // Copy the data - memcpy(dest, data, width*height*4); - - // Unlock the pixel buffer - pixelBuffer->unlock(); -} - - -*/ - -} // nsmaepace NifOgre +} // namespace NifOgre From 2db72ae607926627e95032f7e7d8f177b7da2478 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 01:52:35 -0700 Subject: [PATCH 0319/1537] Rename EntityList to ObjectList --- apps/openmw/mwrender/activatoranimation.cpp | 6 +- apps/openmw/mwrender/animation.cpp | 44 ++++++------ apps/openmw/mwrender/animation.hpp | 4 +- apps/openmw/mwrender/creatureanimation.cpp | 6 +- apps/openmw/mwrender/npcanimation.cpp | 54 +++++++-------- apps/openmw/mwrender/npcanimation.hpp | 6 +- apps/openmw/mwrender/objects.cpp | 26 +++---- apps/openmw/mwrender/sky.cpp | 18 ++--- components/nifogre/ogrenifloader.cpp | 76 ++++++++++----------- components/nifogre/ogrenifloader.hpp | 18 ++--- 10 files changed, 129 insertions(+), 129 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 961c070038..b1b820915d 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -25,10 +25,10 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) { std::string mesh = "meshes\\" + ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(mPtr.getRefData().getBaseNode(), mesh); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *ent = mEntityList.mEntities[i]; + Ogre::Entity *ent = mObjectList.mEntities[i]; for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2b980320da..1d983acfc5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -40,21 +40,21 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mEntityList.mParticles.size();i++) - sceneMgr->destroyParticleSystem(mEntityList.mParticles[i]); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) - sceneMgr->destroyEntity(mEntityList.mEntities[i]); + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + sceneMgr->destroyParticleSystem(mObjectList.mParticles[i]); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) + sceneMgr->destroyEntity(mObjectList.mEntities[i]); } - mEntityList.mControllers.clear(); - mEntityList.mParticles.clear(); - mEntityList.mEntities.clear(); - mEntityList.mSkelBase = NULL; + mObjectList.mControllers.clear(); + mObjectList.mParticles.clear(); + mObjectList.mEntities.clear(); + mObjectList.mSkelBase = NULL; } void Animation::setAnimationSources(const std::vector &names) { - if(!mEntityList.mSkelBase) + if(!mObjectList.mSkelBase) return; mCurrentAnim = NULL; @@ -87,7 +87,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mEntityList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); } mSkeletonSources.push_back(skel); @@ -105,15 +105,15 @@ void Animation::setAnimationSources(const std::vector &names) } } -void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { mInsert = node->createChildSceneNode(); assert(mInsert); - mEntityList = NifOgre::Loader::createEntities(mInsert, model); - if(mEntityList.mSkelBase) + mObjectList = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mEntityList.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -125,17 +125,17 @@ void Animation::createEntityList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mEntityList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mEntityList.mControllers.size();i++) + for(size_t i = 0;i < mObjectList.mControllers.size();i++) { - if(mEntityList.mControllers[i].getSource().isNull()) - mEntityList.mControllers[i].setSource(ctrlval); + if(mObjectList.mControllers[i].getSource().isNull()) + mObjectList.mControllers[i].setSource(ctrlval); } } @@ -242,7 +242,7 @@ void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::Sk // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mEntityList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -289,7 +289,7 @@ Ogre::Vector3 Animation::updatePosition(float time) mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); else mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); - applyAnimation(mCurrentAnim, mCurrentTime, mEntityList.mSkelBase->getSkeleton()); + applyAnimation(mCurrentAnim, mCurrentTime, mObjectList.mSkelBase->getSkeleton()); Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; if(mNonAccumRoot) @@ -465,8 +465,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mEntityList.mControllers.size();i++) - mEntityList.mControllers[i].update(); + for(size_t i = 0;i < mObjectList.mControllers.size();i++) + mObjectList.mControllers[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3e7dee6db2..55aaca427c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -40,7 +40,7 @@ protected: MWMechanics::CharacterController *mController; Ogre::SceneNode* mInsert; - NifOgre::EntityList mEntityList; + NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; @@ -91,7 +91,7 @@ protected: setAnimationSources(names); } - void createEntityList(Ogre::SceneNode *node, const std::string &model); + void createObjectList(Ogre::SceneNode *node, const std::string &model); public: Animation(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 22f84ee018..a8c4afc4e8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,10 +25,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createEntityList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(mPtr.getRefData().getBaseNode(), model); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *ent = mEntityList.mEntities[i]; + Ogre::Entity *ent = mObjectList.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b7bcad5995..5d14440e75 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -50,7 +50,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize NpcAnimation::~NpcAnimation() { for(size_t i = 0;i < sPartListSize;i++) - removeEntities(mEntityParts[i]); + removeObjects(mObjectParts[i]); } @@ -94,10 +94,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createEntityList(node, smodel); - for(size_t i = 0;i < mEntityList.mEntities.size();i++) + createObjectList(node, smodel); + for(size_t i = 0;i < mObjectList.mEntities.size();i++) { - Ogre::Entity *base = mEntityList.mEntities[i]; + Ogre::Entity *base = mObjectList.mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -302,11 +302,11 @@ void NpcAnimation::updateParts(bool forceupdate) } } -NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int group, const std::string &bonename) +NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::EntityList entities = NifOgre::Loader::createEntities(mEntityList.mSkelBase, bonename, - mInsert, mesh); - std::vector &parts = entities.mEntities; + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, + mInsert, model); + const std::vector &parts = objects.mEntities; for(size_t i = 0;i < parts.size();i++) { parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -319,9 +319,9 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - if(entities.mSkelBase) + if(objects.mSkelBase) { - Ogre::AnimationStateSet *aset = entities.mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -329,12 +329,12 @@ NifOgre::EntityList NpcAnimation::insertBoundedPart(const std::string &mesh, int state->setEnabled(false); state->setLoop(false); } - Ogre::SkeletonInstance *skelinst = entities.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objects.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } - return entities; + return objects; } Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) @@ -347,10 +347,10 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mEntityList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { - Ogre::Entity *ent = mEntityParts[i].mSkelBase; + Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; updateSkeletonInstance(skelsrc, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); @@ -358,19 +358,19 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } -void NpcAnimation::removeEntities(NifOgre::EntityList &entities) +void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) { - assert(&entities != &mEntityList); + assert(&objects != &mObjectList); Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < entities.mParticles.size();i++) - sceneMgr->destroyParticleSystem(entities.mParticles[i]); - for(size_t i = 0;i < entities.mEntities.size();i++) - sceneMgr->destroyEntity(entities.mEntities[i]); - entities.mControllers.clear(); - entities.mParticles.clear(); - entities.mEntities.clear(); - entities.mSkelBase = NULL; + for(size_t i = 0;i < objects.mParticles.size();i++) + sceneMgr->destroyParticleSystem(objects.mParticles[i]); + for(size_t i = 0;i < objects.mEntities.size();i++) + sceneMgr->destroyEntity(objects.mEntities[i]); + objects.mControllers.clear(); + objects.mParticles.clear(); + objects.mEntities.clear(); + objects.mSkelBase = NULL; } void NpcAnimation::removeIndividualPart(int type) @@ -382,7 +382,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeEntities(mEntityParts[i]); + removeObjects(mObjectParts[i]); break; } } @@ -420,7 +420,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, { if(type == sPartList[i].type) { - mEntityParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); + mObjectParts[i] = insertBoundedPart(mesh, group, sPartList[i].name); break; } } @@ -451,7 +451,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); + return mObjectList.mSkelBase->getSkeleton()->getBone("Bip01 Head"); } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 5da4afef8a..41c29f7638 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -33,7 +33,7 @@ private: int mStateID; // Bounded Parts - NifOgre::EntityList mEntityParts[sPartListSize]; + NifOgre::ObjectList mObjectParts[sPartListSize]; const ESM::NPC *mNpc; std::string mHeadModel; @@ -60,11 +60,11 @@ private: int mPartslots[sPartListSize]; //Each part slot is taken by clothing, armor, or is empty int mPartPriorities[sPartListSize]; - NifOgre::EntityList insertBoundedPart(const std::string &mesh, int group, const std::string &bonename); + NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename); void updateParts(bool forceupdate = false); - void removeEntities(NifOgre::EntityList &entities); + void removeObjects(NifOgre::ObjectList &objects); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 8c5d4cad3a..3456e1c16a 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -130,9 +130,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; - NifOgre::EntityList entities = NifOgre::Loader::createEntities(insert, mesh); - for(size_t i = 0;i < entities.mEntities.size();i++) - bounds.merge(entities.mEntities[i]->getWorldBoundingBox(true)); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(insert, mesh); + for(size_t i = 0;i < objects.mEntities.size();i++) + bounds.merge(objects.mEntities[i]->getWorldBoundingBox(true)); Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); @@ -149,9 +149,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool mBounds[ptr.getCell()].merge(bounds); bool anyTransparency = false; - for(size_t i = 0;!anyTransparency && i < entities.mEntities.size();i++) + for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++) { - Ogre::Entity *ent = entities.mEntities[i]; + Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i) { anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent(); @@ -159,11 +159,11 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || - anyTransparency || entities.mParticles.size() > 0) + anyTransparency || objects.mParticles.size() > 0) { - for(size_t i = 0;i < entities.mEntities.size();i++) + for(size_t i = 0;i < objects.mEntities.size();i++) { - Ogre::Entity *ent = entities.mEntities[i]; + Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0; i < ent->getNumSubEntities(); ++i) { Ogre::SubEntity* subEnt = ent->getSubEntity(i); @@ -172,9 +172,9 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } - for(size_t i = 0;i < entities.mParticles.size();i++) + for(size_t i = 0;i < objects.mParticles.size();i++) { - Ogre::ParticleSystem *part = entities.mParticles[i]; + Ogre::ParticleSystem *part = objects.mParticles[i]; // TODO: Check the particle system's material for actual transparency part->setRenderQueueGroup(RQG_Alpha); part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); @@ -225,8 +225,8 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool sg->setRenderQueueGroup(RQG_Main); - std::vector::reverse_iterator iter = entities.mEntities.rbegin(); - while(iter != entities.mEntities.rend()) + std::vector::reverse_iterator iter = objects.mEntities.rbegin(); + while(iter != objects.mEntities.rend()) { Ogre::Node *node = (*iter)->getParentNode(); sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); @@ -239,7 +239,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool if (light) { - insertLight(ptr, entities.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); + insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 94af3521b3..7f3abce701 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -288,10 +288,10 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::EntityList entities = NifOgre::Loader::createEntities(mAtmosphereNight, "meshes\\sky_night_01.nif"); - for(size_t i = 0, matidx = 0;i < entities.mEntities.size();i++) + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + for(size_t i = 0, matidx = 0;i < objects.mEntities.size();i++) { - Entity* night1_ent = entities.mEntities[i]; + Entity* night1_ent = objects.mEntities[i]; night1_ent->setRenderQueueGroup(RQG_SkiesEarly+1); night1_ent->setVisibilityFlags(RV_Sky); night1_ent->setCastShadows(false); @@ -314,10 +314,10 @@ void SkyManager::create() // Atmosphere (day) mAtmosphereDay = mRootNode->createChildSceneNode(); - entities = NifOgre::Loader::createEntities(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + objects = NifOgre::Loader::createObjects(mAtmosphereDay, "meshes\\sky_atmosphere.nif"); + for(size_t i = 0;i < objects.mEntities.size();i++) { - Entity* atmosphere_ent = entities.mEntities[i]; + Entity* atmosphere_ent = objects.mEntities[i]; atmosphere_ent->setCastShadows(false); atmosphere_ent->setRenderQueueGroup(RQG_SkiesEarly); atmosphere_ent->setVisibilityFlags(RV_Sky); @@ -332,10 +332,10 @@ void SkyManager::create() // Clouds SceneNode* clouds_node = mRootNode->createChildSceneNode(); - entities = NifOgre::Loader::createEntities(clouds_node, "meshes\\sky_clouds_01.nif"); - for(size_t i = 0;i < entities.mEntities.size();i++) + objects = NifOgre::Loader::createObjects(clouds_node, "meshes\\sky_clouds_01.nif"); + for(size_t i = 0;i < objects.mEntities.size();i++) { - Entity* clouds_ent = entities.mEntities[i]; + Entity* clouds_ent = objects.mEntities[i]; clouds_ent->setVisibilityFlags(RV_Sky); clouds_ent->setRenderQueueGroup(RQG_SkiesEarly+5); for(unsigned int j = 0;j < clouds_ent->getNumSubEntities();j++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 99c6a65dcf..e7d1a88d1c 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1421,7 +1421,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader createSubMesh(mesh, dynamic_cast(record)); } - void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities, int flags=0) + void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags=0) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -1460,12 +1460,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::SharedPtr > srcval; /* Filled in later */ Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); - entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } @@ -1494,16 +1494,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::Entity *entity = sceneMgr->createEntity(mesh); entity->setVisible(!(flags&0x01)); - entities.mEntities.push_back(entity); - if(entities.mSkelBase) + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) { if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(entities.mSkelBase); + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); else { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); - Ogre::Bone *trgtbone = entities.mSkelBase->getSkeleton()->getBone(trgtid); - entities.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } } @@ -1519,7 +1519,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); - entities.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } @@ -1528,11 +1528,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) { - Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, entities.mSkelBase, node); + Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) { partsys->setVisible(!(flags&0x01)); - entities.mParticles.push_back(partsys); + objectlist.mParticles.push_back(partsys); } } @@ -1543,12 +1543,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(sceneMgr, children[i].getPtr(), entities, flags); + createObjects(sceneMgr, children[i].getPtr(), objectlist, flags); } } } - void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, EntityList &entities) + void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all @@ -1567,15 +1567,15 @@ class NIFObjectLoader : Ogre::ManualResourceLoader mesh = meshMgr.createManual(fullname, mGroup, loader); mesh->setAutoBuildEdgeLists(false); } - entities.mSkelBase = sceneMgr->createEntity(mesh); - entities.mEntities.push_back(entities.mSkelBase); + objectlist.mSkelBase = sceneMgr->createEntity(mesh); + objectlist.mEntities.push_back(objectlist.mSkelBase); } public: NIFObjectLoader() : mShapeIndex(~(size_t)0) { } - static void load(Ogre::SceneManager *sceneMgr, EntityList &entities, const std::string &name, const std::string &group) + static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) { Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); Nif::NIFFile &nif = *pnif.get(); @@ -1603,44 +1603,44 @@ public: NIFObjectLoader meshldr(name, group); if(hasSkel) - meshldr.createSkelBase(sceneMgr, node, entities); - meshldr.createObjects(sceneMgr, node, entities); + meshldr.createSkelBase(sceneMgr, node, objectlist); + meshldr.createObjects(sceneMgr, node, objectlist); } }; NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; -EntityList Loader::createEntities(Ogre::SceneNode *parentNode, std::string name, const std::string &group) +ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { - EntityList entitylist; + ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group); - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(!entity->isAttached()) parentNode->attachObject(entity); } - return entitylist; + return objectlist; } -EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, const std::string &group) +ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, const std::string &group) { - EntityList entitylist; + ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(parentNode->getCreator(), entitylist, name, group); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group); bool isskinned = false; - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *ent = entitylist.mEntities[i]; - if(entitylist.mSkelBase != ent && ent->hasSkeleton()) + Ogre::Entity *ent = objectlist.mEntities[i]; + if(objectlist.mSkelBase != ent && ent->hasSkeleton()) { isskinned = true; break; @@ -1655,12 +1655,12 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen { std::string filter = "@shape=tri "+bonename; Misc::StringUtils::toLower(filter); - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(entity->hasSkeleton()) { - if(entity == entitylist.mSkelBase || + if(entity == objectlist.mSkelBase || entity->getMesh()->getName().find(filter) != std::string::npos) parentNode->attachObject(entity); } @@ -1673,9 +1673,9 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } else { - for(size_t i = 0;i < entitylist.mEntities.size();i++) + for(size_t i = 0;i < objectlist.mEntities.size();i++) { - Ogre::Entity *entity = entitylist.mEntities[i]; + Ogre::Entity *entity = objectlist.mEntities[i]; if(!entity->isAttached()) { Ogre::TagPoint *tag = parent->attachObjectToBone(bonename, entity); @@ -1684,7 +1684,7 @@ EntityList Loader::createEntities(Ogre::Entity *parent, const std::string &bonen } } - return entitylist; + return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 819b4d8806..ee50aa86e5 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -39,7 +39,7 @@ namespace NifOgre typedef std::multimap TextKeyMap; static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; -struct EntityList { +struct ObjectList { Ogre::Entity *mSkelBase; std::vector mEntities; @@ -47,7 +47,7 @@ struct EntityList { std::vector > mControllers; - EntityList() : mSkelBase(0) + ObjectList() : mSkelBase(0) { } }; @@ -55,14 +55,14 @@ struct EntityList { class Loader { public: - static EntityList createEntities(Ogre::Entity *parent, const std::string &bonename, - Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); + static ObjectList createObjects(Ogre::Entity *parent, const std::string &bonename, + Ogre::SceneNode *parentNode, + std::string name, + const std::string &group="General"); - static EntityList createEntities(Ogre::SceneNode *parentNode, - std::string name, - const std::string &group="General"); + static ObjectList createObjects(Ogre::SceneNode *parentNode, + std::string name, + const std::string &group="General"); static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); }; From 878b4c15c5631fa3daa75a80d1fd44cb7e917a36 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 02:08:33 -0700 Subject: [PATCH 0320/1537] Set visibility flags and the render queue group for particles --- apps/openmw/mwrender/activatoranimation.cpp | 9 ++++++- apps/openmw/mwrender/creatureanimation.cpp | 8 ++++++ apps/openmw/mwrender/npcanimation.cpp | 30 ++++++++++++++++----- 3 files changed, 39 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index b1b820915d..4630208b4b 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,6 +1,7 @@ #include "activatoranimation.hpp" #include +#include #include #include @@ -29,14 +30,20 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) for(size_t i = 0;i < mObjectList.mEntities.size();i++) { Ogre::Entity *ent = mObjectList.mEntities[i]; + ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) { Ogre::SubEntity* subEnt = ent->getSubEntity(j); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } + } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + part->setVisibilityFlags(RV_Misc); - ent->setVisibilityFlags(RV_Misc); + part->setRenderQueueGroup(RQG_Alpha); } setAnimationSource(mesh); } diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a8c4afc4e8..c714a2372a 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,6 +1,7 @@ #include "creatureanimation.hpp" #include +#include #include #include @@ -37,6 +38,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + part->setVisibilityFlags(RV_Actors); + + part->setRenderQueueGroup(RQG_Alpha); + } std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 5d14440e75..28c78fd2f7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" @@ -109,6 +110,15 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < mObjectList.mParticles.size();i++) + { + Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + + part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); + if(mVisibilityFlags != 0) + part->setVisibilityFlags(mVisibilityFlags); + part->setRenderQueueGroup(RQG_Alpha); + } std::vector skelnames(1, smodel); if(!mNpc->isMale() && !isBeast) @@ -306,19 +316,25 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, mInsert, model); - const std::vector &parts = objects.mEntities; - for(size_t i = 0;i < parts.size();i++) + for(size_t i = 0;i < objects.mEntities.size();i++) { - parts[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if (mVisibilityFlags != 0) - parts[i]->setVisibilityFlags(mVisibilityFlags); + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + if(mVisibilityFlags != 0) + objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); - for(unsigned int j=0; j < parts[i]->getNumSubEntities(); ++j) + for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) { - Ogre::SubEntity* subEnt = parts[i]->getSubEntity(j); + Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } + for(size_t i = 0;i < objects.mParticles.size();i++) + { + objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); + if(mVisibilityFlags != 0) + objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); + objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); + } if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); From be419bc89185c74be619d08054e94e8aad0cec71 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 02:28:15 -0700 Subject: [PATCH 0321/1537] Handle NiCamera nodes --- apps/openmw/mwrender/animation.cpp | 1 + apps/openmw/mwrender/npcanimation.cpp | 1 + components/nifogre/ogrenifloader.cpp | 8 ++++++++ components/nifogre/ogrenifloader.hpp | 7 ++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 1d983acfc5..23d2d9e1b6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -46,6 +46,7 @@ Animation::~Animation() sceneMgr->destroyEntity(mObjectList.mEntities[i]); } mObjectList.mControllers.clear(); + mObjectList.mCameras.clear(); mObjectList.mParticles.clear(); mObjectList.mEntities.clear(); mObjectList.mSkelBase = NULL; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 28c78fd2f7..931b8ef83d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -384,6 +384,7 @@ void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) for(size_t i = 0;i < objects.mEntities.size();i++) sceneMgr->destroyEntity(objects.mEntities[i]); objects.mControllers.clear(); + objects.mCameras.clear(); objects.mParticles.clear(); objects.mEntities.clear(); objects.mSkelBase = NULL; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e7d1a88d1c..7dd616e4ee 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -498,6 +498,7 @@ void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animro if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles )) @@ -1452,6 +1453,13 @@ class NIFObjectLoader : Ogre::ManualResourceLoader e = e->extra; } + if(node->recType == Nif::RC_NiCamera) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, node->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mCameras.push_back(trgtbone); + } + Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index ee50aa86e5..88cbaf6910 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -42,9 +42,14 @@ static const char sTextKeyExtraDataID[] = "TextKeyExtraData"; struct ObjectList { Ogre::Entity *mSkelBase; std::vector mEntities; - std::vector mParticles; + // We could actually have Ogre::Camera objects, but that means more + // maintenance when switching cameras. The information in the NiCamera node + // is pretty much useless too anyway. So instead, this is just a list of + // bones in the mSkelBase which are NiCamera nodes. + std::vector mCameras; + std::vector > mControllers; ObjectList() : mSkelBase(0) From ff1d908af416d8301dda9f1f82d8947c1213d4f4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 15:17:35 +0200 Subject: [PATCH 0322/1537] added script table --- apps/esmtool/record.cpp | 2 +- apps/opencs/model/world/data.cpp | 15 +++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadscpt.cpp | 15 +++++++++++++-- components/esm/loadscpt.hpp | 5 ++++- 10 files changed, 56 insertions(+), 5 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a6f77862ef..e16ade6e24 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -1182,7 +1182,7 @@ void Record::print() std::cout << " Variable: " << *vit << std::endl; std::cout << " ByteCode: "; - std::vector::iterator cit; + std::vector::iterator cit; for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); cit++) std::cout << boost::format("%02X") % (int)(*cit); std::cout << std::endl; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 69109bd743..c29cdaccfb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -84,6 +84,9 @@ CSMWorld::Data::Data() mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); mSounds.addColumn (new SoundFileColumn); + mScripts.addColumn (new StringIdColumn); + mScripts.addColumn (new RecordStateColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -91,6 +94,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); + addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); } CSMWorld::Data::~Data() @@ -169,6 +173,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSounds() return mSounds; } +const CSMWorld::IdCollection& CSMWorld::Data::getScripts() const +{ + return mScripts; +} + +CSMWorld::IdCollection& CSMWorld::Data::getScripts() +{ + return mScripts; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -210,6 +224,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; + case ESM::REC_SCPT: mScripts.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 320480e639..7daf5d4baa 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -30,6 +31,7 @@ namespace CSMWorld IdCollection mFactions; IdCollection mRaces; IdCollection mSounds; + IdCollection mScripts; std::vector mModels; std::map mModelIndex; @@ -74,6 +76,10 @@ namespace CSMWorld IdCollection& getSounds(); + const IdCollection& getScripts() const; + + IdCollection& getScripts(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 7bdc15c8c7..816681a133 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -24,6 +24,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Factions, "Factions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -37,6 +38,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Faction, "Faction" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index a21d67fcd8..06db75d7f4 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -47,7 +47,9 @@ namespace CSMWorld Type_Races, Type_Race, Type_Sounds, - Type_Sound + Type_Sound, + Type_Scripts, + Type_Script }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 611690ca65..27cf78b3ce 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -109,6 +109,10 @@ void CSVDoc::View::setupWorldMenu() QAction *sounds = new QAction (tr ("Sounds"), this); connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView())); world->addAction (sounds); + + QAction *scripts = new QAction (tr ("Scripts"), this); + connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); + world->addAction (scripts); } void CSVDoc::View::setupUi() @@ -289,6 +293,11 @@ void CSVDoc::View::addSoundsSubView() addSubView (CSMWorld::UniversalId::Type_Sounds); } +void CSVDoc::View::addScriptsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Scripts); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index e8e716b706..4822db3e4f 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -125,6 +125,8 @@ namespace CSVDoc void addRacesSubView(); void addSoundsSubView(); + + void addScriptsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 3ba950f879..7cdf18bce6 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -21,6 +21,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, + CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index d9b6497d98..2c1b018d97 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -64,7 +64,7 @@ void Script::save(ESMWriter &esm) memcpy(data.mName.name, mId.c_str(), mId.size()); esm.writeHNT("SCHD", data, 52); - + if (!mVarNames.empty()) { esm.startSubRecord("SCVR"); @@ -76,10 +76,21 @@ void Script::save(ESMWriter &esm) } esm.startSubRecord("SCDT"); - esm.write(&mScriptData[0], mData.mScriptDataSize); + esm.write(reinterpret_cast(&mScriptData[0]), mData.mScriptDataSize); esm.endRecord("SCDT"); esm.writeHNOString("SCTX", mScriptText); } + void Script::blank() + { + mData.mNumShorts = mData.mNumLongs = mData.mNumFloats = 0; + mData.mScriptDataSize = 0; + mData.mStringTableSize = 0; + + mVarNames.clear(); + mScriptData.clear(); + mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n"; + } + } diff --git a/components/esm/loadscpt.hpp b/components/esm/loadscpt.hpp index 10a6d24b10..be7e839002 100644 --- a/components/esm/loadscpt.hpp +++ b/components/esm/loadscpt.hpp @@ -52,11 +52,14 @@ public: SCHDstruct mData; std::vector mVarNames; // Variable names - std::vector mScriptData; // Compiled bytecode + std::vector mScriptData; // Compiled bytecode std::string mScriptText; // Uncompiled script void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 755a80a522963f6d6b26f39134bd6696c917756c Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 15:52:43 +0200 Subject: [PATCH 0323/1537] Fix camera shaking when near the pitch limit. --- apps/openmw/mwrender/player.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 63396378d0..55fda326fa 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -242,14 +242,15 @@ namespace MWRender void Player::setPitch(float angle) { - float limit = Ogre::Math::HALF_PI; + const float epsilon = 0.000001; + float limit = Ogre::Math::HALF_PI - epsilon; if (mVanity.forced || mPreviewMode) { limit /= 2; } if (angle > limit) { - angle = limit - 0.01; + angle = limit; } else if (angle < -limit) { - angle = -limit + 0.01; + angle = -limit; } if (mVanity.enabled || mPreviewMode) { mPreviewCam.pitch = angle; From ebff64a7a4b297c2b9a34a808c19d4b57ee8dee9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 06:56:12 -0700 Subject: [PATCH 0324/1537] Fix UVController and add warn about unhandled material controllers --- components/nifogre/ogrenifloader.cpp | 63 ++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 7dd616e4ee..8924056e03 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -184,18 +184,23 @@ public: static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) { - Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()); + if(keys.mKeys.size() == 0) + return def; + + if(time <= keys.mKeys.front().mTime) + return keys.mKeys.front().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1); for(;iter != keys.mKeys.end();iter++) { - if(iter->mTime > time) + if(iter->mTime < time) continue; - Nif::FloatKeyList::VecType::const_iterator next(iter+1); - if(next == keys.mKeys.end()) - return iter->mValue; - float a = (time-iter->mTime) / (next->mTime-iter->mTime); - return iter->mValue + ((next->mValue - iter->mValue)*a); + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); } - return def; + return keys.mKeys.back().mValue; } public: @@ -837,6 +842,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, else warn("Found internal texture, ignoring."); } + + Nif::ControllerPtr ctrls = texprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled texture controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); @@ -845,6 +857,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, { alphaFlags = alphaprop->flags; alphaTest = alphaprop->data.threshold; + + Nif::ControllerPtr ctrls = alphaprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled alpha controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } // Vertex color handling @@ -853,17 +872,38 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, vertMode = vertprop->data.vertmode; // FIXME: Handle lightmode? //lightMode = vertprop->data.lightmode; + + Nif::ControllerPtr ctrls = vertprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } if(zprop) { depthFlags = zprop->flags; // Depth function??? + + Nif::ControllerPtr ctrls = zprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled depth controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } if(specprop) { specFlags = specprop->flags; + + Nif::ControllerPtr ctrls = specprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled specular controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } // Material @@ -875,6 +915,13 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, emissive = matprop->data.emissive; glossiness = matprop->data.glossiness; alpha = matprop->data.alpha; + + Nif::ControllerPtr ctrls = matprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled material controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } } { From 2e067e95a9a63bbb25d12ecbe6fb969a4e638317 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:12:52 -0700 Subject: [PATCH 0325/1537] Handle NiWireframeProperty --- components/nifogre/ogrenifloader.cpp | 37 +++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8924056e03..94cb14b588 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -799,6 +799,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, const Nif::NiVertexColorProperty *vertprop, const Nif::NiZBufferProperty *zprop, const Nif::NiSpecularProperty *specprop, + const Nif::NiWireframeProperty *wireprop, bool &needTangents) { Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); @@ -819,6 +820,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, int depthFlags = 3; // Default should be 1, but Bloodmoon's models are broken int specFlags = 0; + int wireFlags = 0; Ogre::String texName[7]; bool vertexColour = (shapedata->colors.size() != 0); @@ -906,6 +908,18 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, } } + if(wireprop) + { + wireFlags = wireprop->flags; + + Nif::ControllerPtr ctrls = wireprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + // Material if(matprop) { @@ -950,6 +964,7 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, boost::hash_combine(h, vertMode); boost::hash_combine(h, depthFlags); boost::hash_combine(h, specFlags); + boost::hash_combine(h, wireFlags); std::map::iterator itr = MaterialMap.find(h); if (itr != MaterialMap.end()) @@ -993,6 +1008,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); } + if(wireFlags) + { + instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); + } + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); @@ -1087,10 +1107,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiAlphaProperty *&alphaprop, const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop) + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *wireprop) { if(node->parent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); const Nif::PropertyList &proplist = node->props; for(size_t i = 0;i < proplist.length();i++) @@ -1112,6 +1133,8 @@ class NIFObjectLoader : Ogre::ManualResourceLoader zprop = static_cast(pr); else if(pr->recType == Nif::RC_NiSpecularProperty) specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); else warn("Unhandled property type: "+pr->recName); } @@ -1324,13 +1347,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - needTangents); + wireprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); @@ -1405,13 +1429,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop); + getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, - needTangents)); + wireprop, needTangents)); partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); partsys->setCullIndividually(false); From 8bbfba3f43afa56d62c63b310700384d50fcfaa4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 16:18:40 +0200 Subject: [PATCH 0326/1537] Fix fatigue not being set to its maximum value when player is rebuilt --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 8757213e99..4a2a2ecc69 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -149,7 +149,7 @@ namespace MWMechanics // forced update and current value adjustments mActors.updateActor (ptr, 0); - for (int i=0; i<2; ++i) + for (int i=0; i<3; ++i) { DynamicStat stat = creatureStats.getDynamic (i); stat.setCurrent (stat.getModified()); From e25f5c6dfe71b5c076ccd01dce5048f575ac5aa5 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 16:32:06 +0200 Subject: [PATCH 0327/1537] added basic region table --- apps/opencs/model/world/data.cpp | 16 ++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadregn.cpp | 19 ++++++++++++++++--- components/esm/loadregn.hpp | 3 +++ 9 files changed, 58 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c29cdaccfb..0c6f2b4ada 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -87,6 +87,10 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); + mRegions.addColumn (new StringIdColumn); + mRegions.addColumn (new RecordStateColumn); + mRegions.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -95,6 +99,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); + addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); } CSMWorld::Data::~Data() @@ -183,6 +188,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getScripts() return mScripts; } +const CSMWorld::IdCollection& CSMWorld::Data::getRegions() const +{ + return mRegions; +} + +CSMWorld::IdCollection& CSMWorld::Data::getRegions() +{ + return mRegions; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -225,6 +240,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; + case ESM::REC_REGN: mRegions.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 7daf5d4baa..d9432aa3e3 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -32,6 +33,7 @@ namespace CSMWorld IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; + IdCollection mRegions; std::vector mModels; std::map mModelIndex; @@ -80,6 +82,10 @@ namespace CSMWorld IdCollection& getScripts(); + const IdCollection& getRegions() const; + + IdCollection& getRegions(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 816681a133..4a81ee01b5 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -25,6 +25,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Races, "Races" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -39,6 +40,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Race, "Race" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 06db75d7f4..507febba44 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -49,7 +49,9 @@ namespace CSMWorld Type_Sounds, Type_Sound, Type_Scripts, - Type_Script + Type_Script, + Type_Regions, + Type_Region }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 27cf78b3ce..8e51ba9dcb 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -113,6 +113,10 @@ void CSVDoc::View::setupWorldMenu() QAction *scripts = new QAction (tr ("Scripts"), this); connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView())); world->addAction (scripts); + + QAction *regions = new QAction (tr ("Regions"), this); + connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); + world->addAction (regions); } void CSVDoc::View::setupUi() @@ -298,6 +302,11 @@ void CSVDoc::View::addScriptsSubView() addSubView (CSMWorld::UniversalId::Type_Scripts); } +void CSVDoc::View::addRegionsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Regions); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 4822db3e4f..a5190dedc6 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -127,6 +127,8 @@ namespace CSVDoc void addSoundsSubView(); void addScriptsSubView(); + + void addRegionsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 7cdf18bce6..30812f8f58 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -22,6 +22,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Scripts, + CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp index d39a294547..41c7f507ae 100644 --- a/components/esm/loadregn.cpp +++ b/components/esm/loadregn.cpp @@ -31,14 +31,14 @@ void Region::load(ESMReader &esm) void Region::save(ESMWriter &esm) { esm.writeHNCString("FNAM", mName); - + if (esm.getVersion() == VER_12) esm.writeHNT("WEAT", mData, sizeof(mData) - 2); else esm.writeHNT("WEAT", mData); - + esm.writeHNOCString("BNAM", mSleepList); - + esm.writeHNT("CNAM", mMapColor); for (std::vector::iterator it = mSoundList.begin(); it != mSoundList.end(); ++it) { @@ -46,4 +46,17 @@ void Region::save(ESMWriter &esm) } } + void Region::blank() + { + mName.clear(); + + mData.mClear = mData.mCloudy = mData.mFoggy = mData.mOvercast = mData.mRain = + mData.mThunder = mData.mAsh, mData.mBlight = mData.mA = mData.mB = 0; + + mMapColor = 0; + + mName.clear(); + mSleepList.clear(); + mSoundList.clear(); + } } diff --git a/components/esm/loadregn.hpp b/components/esm/loadregn.hpp index 0496ef5af2..f2a3d9a108 100644 --- a/components/esm/loadregn.hpp +++ b/components/esm/loadregn.hpp @@ -48,6 +48,9 @@ struct Region void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 88c81bfb243164d185723dfbe8e266bf58611034 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:38:43 -0700 Subject: [PATCH 0328/1537] Apply polygon_mode to objects --- files/materials/objects.mat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 49df4e3949..957d75db56 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -17,6 +17,7 @@ material openmw_objects_base depth_check default alpha_rejection default transparent_sorting default + polygon_mode default pass { @@ -41,6 +42,7 @@ material openmw_objects_base depth_write $depth_write depth_check $depth_check transparent_sorting $transparent_sorting + polygon_mode $polygon_mode texture_unit diffuseMap { From fe9a7f12b6c21bc6dc4ebc8ac22fb5fc767a0b81 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 07:53:01 -0700 Subject: [PATCH 0329/1537] Material fixes --- components/nifogre/ogrenifloader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 94cb14b588..3bd8b95e58 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -947,9 +947,11 @@ static Ogre::String getMaterial(const Nif::ShapeData *shapedata, boost::hash_combine(h, diffuse.x); boost::hash_combine(h, diffuse.y); boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, alpha); boost::hash_combine(h, specular.x); boost::hash_combine(h, specular.y); boost::hash_combine(h, specular.z); + boost::hash_combine(h, glossiness); boost::hash_combine(h, emissive.x); boost::hash_combine(h, emissive.y); boost::hash_combine(h, emissive.z); @@ -1108,7 +1110,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiVertexColorProperty *&vertprop, const Nif::NiZBufferProperty *&zprop, const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *wireprop) + const Nif::NiWireframeProperty *&wireprop) { if(node->parent) getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); From f49a2a97c5f09a30703448b28cadbe17adf963ce Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 16:56:21 +0200 Subject: [PATCH 0330/1537] added map colour column to region table --- apps/opencs/model/world/columns.hpp | 34 +++++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 35 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 75dfe15c27..b09c931b28 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -5,6 +5,8 @@ #include +#include + #include "columnbase.hpp" namespace CSMWorld @@ -591,6 +593,38 @@ namespace CSMWorld return true; } }; + + /// \todo QColor is a GUI class and should not be in model. Need to think of an alternative + /// solution. + template + struct MapColourColumn : public Column + { + /// \todo Replace Display_Integer with something that displays the colour value more directly. + MapColourColumn() : Column ("Map Colour", ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + int colour = record.get().mMapColor; + + return QColor (colour & 0xff, (colour>>8) & 0xff, (colour>>16) & 0xff); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + QColor colour = data.value(); + + record2.mMapColor = colour.rgb() & 0xffffff; + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0c6f2b4ada..f451656875 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -90,6 +90,7 @@ CSMWorld::Data::Data() mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); mRegions.addColumn (new NameColumn); + mRegions.addColumn (new MapColourColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From ab5980ae187b8e8e71167353368c0598a83bc26f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 08:29:56 -0700 Subject: [PATCH 0331/1537] Let the default controller function use absolute input And convert the VisController to use it. --- components/nifogre/ogrenifloader.cpp | 84 ++++++++++++++-------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3bd8b95e58..e5e072620e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -75,24 +75,33 @@ private: float mStopTime; public: - DefaultFunction(const Nif::Controller *ctrl) - : Ogre::ControllerFunction(false) + DefaultFunction(const Nif::Controller *ctrl, bool deltaInput) + : Ogre::ControllerFunction(deltaInput) , mFrequency(ctrl->frequency) , mPhase(ctrl->phase) , mStartTime(ctrl->timeStart) , mStopTime(ctrl->timeStop) { - mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); + if(mDeltaInput) + { + mDeltaCount = mPhase; + while(mDeltaCount < mStartTime) + mDeltaCount += (mStopTime-mStartTime); + } } virtual Ogre::Real calculate(Ogre::Real value) { - mDeltaCount += value*mFrequency; - mDeltaCount = std::fmod(mDeltaCount - mStartTime, - mStopTime - mStartTime) + mStartTime; - return mDeltaCount; + if(mDeltaInput) + { + mDeltaCount += value*mFrequency; + mDeltaCount = std::fmod(mDeltaCount - mStartTime, + mStopTime - mStartTime) + mStartTime; + return mDeltaCount; + } + + value = std::min(mStopTime, std::max(mStartTime, value+mPhase)); + return value; } }; @@ -103,6 +112,20 @@ public: { private: Ogre::Bone *mTarget; + std::vector mData; + + virtual bool calculate(Ogre::Real time) + { + if(mData.size() == 0) + return true; + + for(size_t i = 1;i < mData.size();i++) + { + if(mData[i].time > time) + return mData[i-1].isSet; + } + return mData.back().isSet; + } // FIXME: We are not getting all objects here. Skinned meshes get // attached to the object's root node, and won't be connected via a @@ -126,7 +149,9 @@ public: } public: - Value(Ogre::Bone *target) : mTarget(target) + Value(Ogre::Bone *target, const Nif::NiVisData *data) + : mTarget(target) + , mData(data->mVis) { } virtual Ogre::Real getValue() const @@ -135,39 +160,14 @@ public: return 1.0f; } - virtual void setValue(Ogre::Real value) + virtual void setValue(Ogre::Real time) { - int vis = static_cast(value); + bool vis = calculate(time); setVisible(mTarget, vis); } }; - class Function : public Ogre::ControllerFunction - { - private: - std::vector mData; - - public: - Function(const Nif::NiVisData *data) - : Ogre::ControllerFunction(false), - mData(data->mVis) - { } - - virtual Ogre::Real calculate(Ogre::Real value) - { - if(mData.size() == 0) - return 1.0f; - - if(mData[0].time >= value) - return mData[0].isSet; - for(size_t i = 1;i < mData.size();i++) - { - if(mData[i].time > value) - return mData[i-1].isSet; - } - return mData.back().isSet; - } - }; + typedef DefaultFunction Function; }; class UVController @@ -1543,9 +1543,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::SharedPtr > srcval; /* Filled in later */ - Ogre::SharedPtr > dstval(OGRE_NEW VisController::Value(trgtbone)); - Ogre::SharedPtr > func(OGRE_NEW VisController::Function(vis->data.getPtr())); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -1599,7 +1599,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 399394ff103ec1f2779cdb8244caccff6da5621e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 10:03:13 -0700 Subject: [PATCH 0332/1537] Don't restrict animations to the keyframe time limits --- components/nifogre/ogrenifloader.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e5e072620e..90139c9f02 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -384,10 +384,8 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const lasttrans = curtrans = traniter->mValue; if(scaleiter != scalekeys.mKeys.end()) lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - float begTime = std::max(kfc->timeStart, startTime); - float endTime = std::min(kfc->timeStop, stopTime); - bool didlast = false; + bool didlast = false; while(!didlast) { float curtime = std::numeric_limits::max(); @@ -400,11 +398,11 @@ static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const if(scaleiter != scalekeys.mKeys.end()) curtime = std::min(curtime, scaleiter->mTime); - curtime = std::max(curtime, begTime); - if(curtime >= endTime) + curtime = std::max(curtime, startTime); + if(curtime >= stopTime) { didlast = true; - curtime = endTime; + curtime = stopTime; } // Get the latest quaternions, translations, and scales for the From 822866b5ae325a8a6a1bf29d1c09f4c8860f9104 Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Sun, 7 Apr 2013 18:04:30 +0100 Subject: [PATCH 0333/1537] fixed autorun --- apps/openmw/mwinput/inputmanagerimp.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 74d581b811..0ed49cd7f7 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -301,6 +301,12 @@ namespace MWInput mPlayer.setForwardBackward (-1); } + else if(mPlayer.getAutoMove()) + { + triedToMove = true; + mPlayer.setForwardBackward (1); + } + mPlayer.setSneak(actionIsActive(A_Sneak)); if (actionIsActive(A_Jump) && mControlSwitch["playerjumping"]) @@ -321,6 +327,7 @@ namespace MWInput mOverencumberedMessageDelay -= dt; if (MWWorld::Class::get(player).getEncumbrance(player) >= MWWorld::Class::get(player).getCapacity(player)) { + mPlayer.setAutoMove (false); if (mOverencumberedMessageDelay <= 0) { MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}"); From c9424f577f15a35a6f1fe22d6681db39a48269fd Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 19:29:15 +0200 Subject: [PATCH 0334/1537] added sleeplist column to region table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b09c931b28..aa097dac65 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -625,6 +625,31 @@ namespace CSMWorld return true; } }; + + template + struct SleepListColumn : public Column + { + SleepListColumn() : Column ("Sleep Encounter", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mSleepList.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mSleepList = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index f451656875..fc93675e42 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -91,6 +91,7 @@ CSMWorld::Data::Data() mRegions.addColumn (new RecordStateColumn); mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); + mRegions.addColumn (new SleepListColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 593646436ea4fe3dcabdb01b40c2fd5d45b0a279 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 19:39:13 +0200 Subject: [PATCH 0335/1537] added verifier for region record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/regioncheck.cpp | 33 +++++++++++++++++++++++++ apps/opencs/model/tools/regioncheck.hpp | 29 ++++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/regioncheck.cpp create mode 100644 apps/opencs/model/tools/regioncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ffd4c7f1ea..301febfc49 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -35,7 +35,7 @@ opencs_units (model/tools ) opencs_units_noqt (model/tools - stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck + stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck ) diff --git a/apps/opencs/model/tools/regioncheck.cpp b/apps/opencs/model/tools/regioncheck.cpp new file mode 100644 index 0000000000..ac64ac0271 --- /dev/null +++ b/apps/opencs/model/tools/regioncheck.cpp @@ -0,0 +1,33 @@ + +#include "regioncheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::RegionCheckStage::RegionCheckStage (const CSMWorld::IdCollection& regions) +: mRegions (regions) +{} + +int CSMTools::RegionCheckStage::setup() +{ + return mRegions.getSize(); +} + +void CSMTools::RegionCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Region& region = mRegions.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Region, region.mId); + + // test for empty name + if (region.mName.empty()) + messages.push_back (id.toString() + "|" + region.mId + " has an empty name"); + + /// \todo test that the ID in mSleeplist exists + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/regioncheck.hpp b/apps/opencs/model/tools/regioncheck.hpp new file mode 100644 index 0000000000..b421356514 --- /dev/null +++ b/apps/opencs/model/tools/regioncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_REGIONCHECK_H +#define CSM_TOOLS_REGIONCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that region records are internally consistent + class RegionCheckStage : public Stage + { + const CSMWorld::IdCollection& mRegions; + + public: + + RegionCheckStage (const CSMWorld::IdCollection& regions); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 4003bc8840..45adcf5e49 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -17,6 +17,7 @@ #include "factioncheck.hpp" #include "racecheck.hpp" #include "soundcheck.hpp" +#include "regioncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -66,6 +67,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new RaceCheckStage (mData.getRaces())); mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); + + mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); } return mVerifier; From 80a1abd48ad5bc37e604c820249d8d7d250cd91c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 11:09:55 -0700 Subject: [PATCH 0336/1537] Clear the old text keys when setting new animation sources --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 23d2d9e1b6..8ecebc7070 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -63,6 +63,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimVelocity = 0.0f; mAccumRoot = NULL; mNonAccumRoot = NULL; + mTextKeys.clear(); mSkeletonSources.clear(); std::vector::const_iterator nameiter; @@ -96,7 +97,7 @@ void Animation::setAnimationSources(const std::vector &names) { Ogre::Animation *anim = skel->getAnimation(i); const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); + "@"+anim->getName()); if(!groupdata.isEmpty()) mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); } From 60cc95305d101c820856684186b7fb3beabf1e8f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 20:26:39 +0200 Subject: [PATCH 0337/1537] added basic birthsign table --- apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadbsgn.cpp | 8 ++++++++ components/esm/loadbsgn.hpp | 3 +++ 9 files changed, 51 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fc93675e42..70162ba758 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -93,6 +93,11 @@ CSMWorld::Data::Data() mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); + mBirthsigns.addColumn (new StringIdColumn); + mBirthsigns.addColumn (new RecordStateColumn); + mBirthsigns.addColumn (new NameColumn); + mBirthsigns.addColumn (new DescriptionColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -102,6 +107,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); + addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); } CSMWorld::Data::~Data() @@ -200,6 +206,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getRegions() return mRegions; } +const CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() const +{ + return mBirthsigns; +} + +CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() +{ + return mBirthsigns; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -243,6 +259,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; + case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index d9432aa3e3..122e855d86 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -34,6 +35,7 @@ namespace CSMWorld IdCollection mSounds; IdCollection mScripts; IdCollection mRegions; + IdCollection mBirthsigns; std::vector mModels; std::map mModelIndex; @@ -86,6 +88,10 @@ namespace CSMWorld IdCollection& getRegions(); + const IdCollection& getBirthsigns() const; + + IdCollection& getBirthsigns(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 4a81ee01b5..6d305d6c0f 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -26,6 +26,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Sounds, "Sounds" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -41,6 +42,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Sound, "Sound" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 507febba44..0586719f14 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -51,7 +51,9 @@ namespace CSMWorld Type_Scripts, Type_Script, Type_Regions, - Type_Region + Type_Region, + Type_Birthsigns, + Type_Birthsign }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 8e51ba9dcb..af9b814203 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -117,6 +117,10 @@ void CSVDoc::View::setupWorldMenu() QAction *regions = new QAction (tr ("Regions"), this); connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView())); world->addAction (regions); + + QAction *birthsigns = new QAction (tr ("Birthsigns"), this); + connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); + world->addAction (birthsigns); } void CSVDoc::View::setupUi() @@ -307,6 +311,11 @@ void CSVDoc::View::addRegionsSubView() addSubView (CSMWorld::UniversalId::Type_Regions); } +void CSVDoc::View::addBirthsignsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Birthsigns); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index a5190dedc6..12944e5693 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -129,6 +129,8 @@ namespace CSVDoc void addScriptsSubView(); void addRegionsSubView(); + + void addBirthsignsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 30812f8f58..23c66319c6 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -23,6 +23,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, + CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp index b58071644c..cb500f6748 100644 --- a/components/esm/loadbsgn.cpp +++ b/components/esm/loadbsgn.cpp @@ -24,4 +24,12 @@ void BirthSign::save(ESMWriter &esm) mPowers.save(esm); } + void BirthSign::blank() + { + mName.clear(); + mDescription.clear(); + mTexture.clear(); + mPowers.mList.clear(); + } + } diff --git a/components/esm/loadbsgn.hpp b/components/esm/loadbsgn.hpp index b0bc28be48..434ddf68ea 100644 --- a/components/esm/loadbsgn.hpp +++ b/components/esm/loadbsgn.hpp @@ -20,6 +20,9 @@ struct BirthSign void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From baf8eaecb82f75168eaac998c9795faa18c3b72e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 20:46:04 +0200 Subject: [PATCH 0338/1537] added texture column to birthsign table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index aa097dac65..fbc533779a 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -650,6 +650,31 @@ namespace CSMWorld return true; } }; + + template + struct TextureColumn : public Column + { + TextureColumn() : Column ("Texture", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mTexture.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mTexture = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 70162ba758..b385c5b4c2 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -96,6 +96,7 @@ CSMWorld::Data::Data() mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); mBirthsigns.addColumn (new NameColumn); + mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); From 2d2196b0d60d4b874af143e370547e72d14ef3ca Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:01:02 +0200 Subject: [PATCH 0339/1537] Implemented levelled items --- apps/openmw/mwworld/containerstore.cpp | 73 ++++++++++++++++++++++---- apps/openmw/mwworld/containerstore.hpp | 1 + components/esm/loadlevlist.hpp | 15 +++--- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index a377f2bbbf..8a5662986e 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -14,6 +14,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/scriptmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -180,21 +182,72 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { - ManualRef ref (store, iter->mItem.toString()); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) - { - /// \todo implement leveled item lists - continue; - } - - ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - addImp (ref.getPtr()); + std::string id = iter->mItem.toString(); + addInitialItem(id, iter->mCount); } flagAsModified(); } +void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, unsigned char failChance, bool topLevel) +{ + count = std::abs(count); /// \todo implement item restocking (indicated by negative count) + + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); + + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + { + const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; + const std::vector& items = levItem->mList; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + { + for (int i=0; i (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) + { + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; + } + + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, count, failChance, false); + } + } + else + { + ref.getPtr().getRefData().setCount (count); + addImp (ref.getPtr()); + } +} + void MWWorld::ContainerStore::clear() { for (ContainerStoreIterator iter (begin()); iter!=end(); ++iter) diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 9d315d27f0..a466c3c2a9 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -53,6 +53,7 @@ namespace MWWorld mutable float mCachedWeight; mutable bool mWeightUpToDate; ContainerStoreIterator addImp (const Ptr& ptr); + void addInitialItem (const std::string& id, int count, unsigned char failChance=0, bool topLevel=true); public: diff --git a/components/esm/loadlevlist.hpp b/components/esm/loadlevlist.hpp index b7db5db360..aa9656d724 100644 --- a/components/esm/loadlevlist.hpp +++ b/components/esm/loadlevlist.hpp @@ -22,17 +22,20 @@ struct LeveledListBase { enum Flags { - AllLevels = 0x01, // Calculate from all levels <= player - // level, not just the closest below - // player. - Each = 0x02 // Select a new item each time this + + Each = 0x01, // Select a new item each time this // list is instantiated, instead of // giving several identical items - }; // (used when a container has more + // (used when a container has more // than one instance of one leveled // list.) + AllLevels = 0x02 // Calculate from all levels <= player + // level, not just the closest below + // player. + }; + int mFlags; - unsigned char mChanceNone; // Chance that none are selected (0-255?) + unsigned char mChanceNone; // Chance that none are selected (0-100) std::string mId; // Record name used to read references. Must be set before load() is From f3c8cd2065ee3f781d3259464e7b1b2943f1f842 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:38:53 +0200 Subject: [PATCH 0340/1537] Don't buy/sell keys which are set to open a lock --- apps/openmw/mwclass/apparatus.cpp | 5 +++++ apps/openmw/mwclass/apparatus.hpp | 2 ++ apps/openmw/mwclass/armor.cpp | 5 +++++ apps/openmw/mwclass/armor.hpp | 2 ++ apps/openmw/mwclass/book.cpp | 5 +++++ apps/openmw/mwclass/book.hpp | 2 ++ apps/openmw/mwclass/clothing.cpp | 5 +++++ apps/openmw/mwclass/clothing.hpp | 2 ++ apps/openmw/mwclass/ingredient.cpp | 5 +++++ apps/openmw/mwclass/ingredient.hpp | 2 ++ apps/openmw/mwclass/light.cpp | 5 +++++ apps/openmw/mwclass/light.hpp | 2 ++ apps/openmw/mwclass/lockpick.cpp | 5 +++++ apps/openmw/mwclass/lockpick.hpp | 2 ++ apps/openmw/mwclass/misc.cpp | 8 ++++++++ apps/openmw/mwclass/misc.hpp | 2 ++ apps/openmw/mwclass/potion.cpp | 5 +++++ apps/openmw/mwclass/potion.hpp | 2 ++ apps/openmw/mwclass/probe.cpp | 5 +++++ apps/openmw/mwclass/probe.hpp | 2 ++ apps/openmw/mwclass/repair.cpp | 5 +++++ apps/openmw/mwclass/repair.hpp | 2 ++ apps/openmw/mwclass/weapon.cpp | 5 +++++ apps/openmw/mwclass/weapon.hpp | 2 ++ apps/openmw/mwgui/tradewindow.cpp | 27 +-------------------------- apps/openmw/mwworld/class.cpp | 5 +++++ apps/openmw/mwworld/class.hpp | 3 +++ components/esm/loadnpc.hpp | 2 +- 28 files changed, 97 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 851a5ae360..32c1277318 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -159,4 +159,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mAppas.insert(*ref), &cell); } + + bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Apparatus; + } } diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index 7045f62d6f..d4917c6186 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -54,6 +54,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 320944d3ce..e62985d3dc 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -315,4 +315,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Armor::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Armor; + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 65f49abb7d..16905d65cc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -74,6 +74,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 85b006160b..b658295f85 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -183,4 +183,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Book::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Books; + } } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index 29e3de0361..3f083f5525 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -59,6 +59,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index abad267675..98480f06f2 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -262,4 +262,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Clothing::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Clothing; + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index c3ef22f113..2e5bb424fb 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -68,6 +68,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 14cf6ff6f9..0afe60e0e2 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -197,4 +197,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mIngreds.insert(*ref), &cell); } + + bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Ingredients; + } } diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 0afd202fb4..d27a7cbb0e 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -56,6 +56,8 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 7466657725..306c6bbb6a 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -203,4 +203,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mLights.insert(*ref), &cell); } + + bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Lights; + } } diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 640e1705bd..7d919f75df 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index 2015726968..bfbf107565 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -176,4 +176,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mLockpicks.insert(*ref), &cell); } + + bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Picks; + } } diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 0961b55b24..edd884a3e0 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index 8cfac1a686..02307cc021 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -246,4 +246,12 @@ namespace MWClass return boost::shared_ptr(new MWWorld::ActionSoulgem(ptr)); } + bool Miscellaneous::canSell (const MWWorld::Ptr& item, int npcServices) const + { + MWWorld::LiveCellRef *ref = + item.get(); + + return !ref->mBase->mData.mIsKey && (npcServices & ESM::NPC::Misc); + } + } diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index 12a50af19d..ba00900bd0 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -53,6 +53,8 @@ namespace MWClass virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; ///< Generate action for using via inventory menu + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 37461ed905..ad2826ea83 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -194,4 +194,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mPotions.insert(*ref), &cell); } + + bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Potions; + } } diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index d595f7e694..845795d0e8 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -52,6 +52,8 @@ namespace MWClass ///< Return name of inventory icon. virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index e4533af655..4ec6a8340b 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -175,4 +175,9 @@ namespace MWClass return MWWorld::Ptr(&cell.mProbes.insert(*ref), &cell); } + + bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Probes; + } } diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index d9f90baf6d..75ebaa01cb 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -57,6 +57,8 @@ namespace MWClass ///< Generate action for using via inventory menu virtual std::string getModel(const MWWorld::Ptr &ptr) const; + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index bafedee88b..36e7068252 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -175,4 +175,9 @@ namespace MWClass { return boost::shared_ptr(new MWWorld::ActionRepair(ptr)); } + + bool Repair::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::RepairItem; + } } diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 3083c97e35..a545cf4d60 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -61,6 +61,8 @@ namespace MWClass virtual int getItemMaxHealth (const MWWorld::Ptr& ptr) const; ///< Return item max health or throw an exception, if class does not have item health /// (default implementation: throw an exceoption) + + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0a527262f8..3df1ced7df 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -409,4 +409,9 @@ namespace MWClass return ref->mBase->mData.mEnchant; } + + bool Weapon::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return npcServices & ESM::NPC::Weapon; + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 4774bb50be..084ceeca2b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -73,6 +73,8 @@ namespace MWClass virtual std::string getModel(const MWWorld::Ptr &ptr) const; + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + virtual short getEnchantmentPoints (const MWWorld::Ptr& ptr) const; }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81a29e69bd..73904371ed 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -356,32 +356,7 @@ namespace MWGui services = ref->mBase->mAiData.mServices; } - /// \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()) - 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::Lockpick).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; + return MWWorld::Class::get(item).canSell(item, services); } std::vector TradeWindow::itemsToIgnore() diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 2dfa241b3b..0f8d40e931 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -47,6 +47,11 @@ namespace MWWorld throw std::runtime_error ("class does not represent an actor"); } + bool Class::canSell (const MWWorld::Ptr& item, int npcServices) const + { + return false; + } + 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 de4741e38b..49e0ff0032 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -238,6 +238,9 @@ namespace MWWorld virtual void adjustRotation(const MWWorld::Ptr& ptr,float& x,float& y,float& z) const; + virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; + ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices + virtual std::string getModel(const MWWorld::Ptr &ptr) const; virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; diff --git a/components/esm/loadnpc.hpp b/components/esm/loadnpc.hpp index 46be29961d..b30077f23c 100644 --- a/components/esm/loadnpc.hpp +++ b/components/esm/loadnpc.hpp @@ -35,11 +35,11 @@ struct NPC Apparatus = 0x00100, RepairItem = 0x00200, Misc = 0x00400, + Potions = 0x02000, // Other services Spells = 0x00800, MagicItems = 0x01000, - Potions = 0x02000, Training = 0x04000, // What skills? Spellmaking = 0x08000, Enchanting = 0x10000, From 2362e920f309b272994cd1763f7e668fc7033de8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 12:41:27 -0700 Subject: [PATCH 0341/1537] Use an unconnected object list for animation sources We'll want the controllers, as the plan is to use their keyframe controllers to animate the actual skeleton used for the meshes. --- apps/openmw/mwrender/animation.cpp | 52 ++++++++++++++++++---------- apps/openmw/mwrender/animation.hpp | 3 +- components/nifogre/ogrenifloader.cpp | 29 +++------------- components/nifogre/ogrenifloader.hpp | 4 ++- 4 files changed, 42 insertions(+), 46 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8ecebc7070..686fbbb848 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -16,6 +16,19 @@ namespace MWRender { +void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) +{ + for(size_t i = 0;i < objects.mParticles.size();i++) + sceneMgr->destroyParticleSystem(objects.mParticles[i]); + for(size_t i = 0;i < objects.mEntities.size();i++) + sceneMgr->destroyEntity(objects.mEntities[i]); + objects.mControllers.clear(); + objects.mCameras.clear(); + objects.mParticles.clear(); + objects.mEntities.clear(); + objects.mSkelBase = NULL; +} + Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) @@ -40,16 +53,12 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectList.mParticles.size();i++) - sceneMgr->destroyParticleSystem(mObjectList.mParticles[i]); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) - sceneMgr->destroyEntity(mObjectList.mEntities[i]); + destroyObjectList(sceneMgr, mObjectList); + + for(size_t i = 0;i < mAnimationSources.size();i++) + destroyObjectList(sceneMgr, mAnimationSources[i]); + mAnimationSources.clear(); } - mObjectList.mControllers.clear(); - mObjectList.mCameras.clear(); - mObjectList.mParticles.clear(); - mObjectList.mEntities.clear(); - mObjectList.mSkelBase = NULL; } @@ -57,6 +66,7 @@ void Animation::setAnimationSources(const std::vector &names) { if(!mObjectList.mSkelBase) return; + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); mCurrentAnim = NULL; mCurrentKeys = NULL; @@ -64,19 +74,24 @@ void Animation::setAnimationSources(const std::vector &names) mAccumRoot = NULL; mNonAccumRoot = NULL; mTextKeys.clear(); - mSkeletonSources.clear(); + for(size_t i = 0;i < mAnimationSources.size();i++) + destroyObjectList(sceneMgr, mAnimationSources[i]); + mAnimationSources.clear(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { - Ogre::SkeletonPtr skel = NifOgre::Loader::getSkeleton(*nameiter); - if(skel.isNull()) + mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); + if(!mAnimationSources.back().mSkelBase) { std::cerr<< "Failed to get skeleton source "<<*nameiter <touch(); + Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { @@ -92,7 +107,6 @@ void Animation::setAnimationSources(const std::vector &names) mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); } - mSkeletonSources.push_back(skel); for(int i = 0;i < skel->getNumAnimations();i++) { Ogre::Animation *anim = skel->getAnimation(i); @@ -144,9 +158,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mSkeletonSources.begin());iter != mSkeletonSources.end();iter++) + for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) { - if((*iter)->hasAnimation(anim)) + if(iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -413,11 +427,11 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mSkeletonSources.rbegin());iter != mSkeletonSources.rend();iter++) + for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { - if((*iter)->hasAnimation(groupname)) + if(iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = (*iter)->getAnimation(groupname); + mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mAnimVelocity = 0.0f; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 55aaca427c..22ab9fc7eb 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -47,7 +47,7 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mSkeletonSources; + std::vector mAnimationSources; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -92,6 +92,7 @@ protected: } void createObjectList(Ogre::SceneNode *node, const std::string &model); + static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: Animation(const MWWorld::Ptr &ptr); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90139c9f02..d3da77e41e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1768,35 +1768,14 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -Ogre::SkeletonPtr Loader::getSkeleton(std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) { - Ogre::SkeletonPtr skel; + ObjectList objectlist; Misc::StringUtils::toLower(name); - skel = Ogre::SkeletonManager::getSingleton().getByName(name); - if(!skel.isNull()) - return skel; + NIFObjectLoader::load(sceneMgr, objectlist, name, group); - Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); - if(nif->numRoots() < 1) - { - nif->warn("Found no root nodes in "+name+"."); - return skel; - } - - // The first record is assumed to be the root node - const Nif::Record *r = nif->getRoot(0); - assert(r != NULL); - - const Nif::Node *node = dynamic_cast(r); - if(node == NULL) - { - nif->warn("First record in "+name+" was not a node, but a "+ - r->recName+"."); - return skel; - } - - return NIFSkeletonLoader::createSkeleton(name, group, node); + return objectlist; } } // namespace NifOgre diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 88cbaf6910..3a7a22f8b1 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,9 @@ public: std::string name, const std::string &group="General"); - static Ogre::SkeletonPtr getSkeleton(std::string name, const std::string &group="General"); + static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + std::string name, + const std::string &group="General"); }; } From 480467b6ebf693004cbc3df2232ff981465a086f Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 21:53:11 +0200 Subject: [PATCH 0342/1537] Reset the 'owner' field for items that were legitimately bought from an NPC. --- apps/openmw/mwgui/tradewindow.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 73904371ed..7756484fa5 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -257,6 +257,12 @@ namespace MWGui MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); // success! make the item transfer. + MWWorld::ContainerStore& playerBoughtItems = mWindowManager.getInventoryWindow()->getBoughtItems(); + for (MWWorld::ContainerStoreIterator it = playerBoughtItems.begin(); it != playerBoughtItems.end(); ++it) + { + if (Misc::StringUtils::ciEqual(it->getCellRef().mOwner, MWWorld::Class::get(mPtr).getId(mPtr))) + it->getCellRef().mOwner = ""; + } transferBoughtItems(); mWindowManager.getInventoryWindow()->transferBoughtItems(); From 7494f90301bcf35a6d3560b495b4f61455b05c9c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 13:02:46 -0700 Subject: [PATCH 0343/1537] Remove an unneeded function --- apps/openmw/mwrender/npcanimation.cpp | 21 +++------------------ apps/openmw/mwrender/npcanimation.hpp | 1 - 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 931b8ef83d..253dbb0ff7 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -50,8 +50,9 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize NpcAnimation::~NpcAnimation() { + Ogre::SceneManager *sceneMgr = mInsert->getCreator(); for(size_t i = 0;i < sPartListSize;i++) - removeObjects(mObjectParts[i]); + destroyObjectList(sceneMgr, mObjectParts[i]); } @@ -374,22 +375,6 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) return ret; } -void NpcAnimation::removeObjects(NifOgre::ObjectList &objects) -{ - assert(&objects != &mObjectList); - - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < objects.mParticles.size();i++) - sceneMgr->destroyParticleSystem(objects.mParticles[i]); - for(size_t i = 0;i < objects.mEntities.size();i++) - sceneMgr->destroyEntity(objects.mEntities[i]); - objects.mControllers.clear(); - objects.mCameras.clear(); - objects.mParticles.clear(); - objects.mEntities.clear(); - objects.mSkelBase = NULL; -} - void NpcAnimation::removeIndividualPart(int type) { mPartPriorities[type] = 0; @@ -399,7 +384,7 @@ void NpcAnimation::removeIndividualPart(int type) { if(type == sPartList[i].type) { - removeObjects(mObjectParts[i]); + destroyObjectList(mInsert->getCreator(), mObjectParts[i]); break; } } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 41c29f7638..b59051a8d6 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -64,7 +64,6 @@ private: void updateParts(bool forceupdate = false); - void removeObjects(NifOgre::ObjectList &objects); void removeIndividualPart(int type); void reserveIndividualPart(int type, int group, int priority); From 44a59e1b87805627390d44d8ba02710476445d7a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 13:03:41 -0700 Subject: [PATCH 0344/1537] Fix a couple messages --- components/nifogre/ogrenifloader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d3da77e41e..d02c0816e3 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1092,12 +1092,12 @@ class NIFObjectLoader : Ogre::ManualResourceLoader static void warn(const std::string &msg) { - std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + std::cerr << "NIFObjectLoader: Warn: " << msg << std::endl; } static void fail(const std::string &msg) { - std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + std::cerr << "NIFObjectLoader: Fail: "<< msg << std::endl; abort(); } From 9e08497f0200b8ea42ad3e6116b868ebca7adbf6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 7 Apr 2013 22:07:04 +0200 Subject: [PATCH 0345/1537] Initial container content should inherit the owner of its container --- apps/openmw/mwworld/cells.cpp | 6 +++--- apps/openmw/mwworld/containerstore.cpp | 11 ++++++----- apps/openmw/mwworld/containerstore.hpp | 4 ++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 5f771be475..4838cfefa5 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -45,7 +45,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, container.getCellRef().mOwner, mStore); } for (CellRefList::List::iterator iter ( @@ -55,7 +55,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, Class::get(container).getId(container), mStore); } for (CellRefList::List::iterator iter ( @@ -65,7 +65,7 @@ void MWWorld::Cells::fillContainers (Ptr::CellStore& cellStore) Ptr container (&*iter, &cellStore); Class::get (container).getContainerStore (container).fill ( - iter->mBase->mInventory, mStore); + iter->mBase->mInventory, Class::get(container).getId(container), mStore); } } diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 8a5662986e..05026a98ba 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -177,19 +177,19 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr return it; } -void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWorld::ESMStore& store) +void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const std::string& owner, const MWWorld::ESMStore& store) { for (std::vector::const_iterator iter (items.mList.begin()); iter!=items.mList.end(); ++iter) { std::string id = iter->mItem.toString(); - addInitialItem(id, iter->mCount); + addInitialItem(id, owner, iter->mCount); } flagAsModified(); } -void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, unsigned char failChance, bool topLevel) +void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std::string& owner, int count, unsigned char failChance, bool topLevel) { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) @@ -208,7 +208,7 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, int count, if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { for (int i=0; i Date: Sun, 7 Apr 2013 13:46:29 -0700 Subject: [PATCH 0346/1537] Update animation source controller targets --- apps/openmw/mwrender/animation.cpp | 14 ++++++++++++++ components/nifogre/ogrenifloader.cpp | 9 ++++----- components/nifogre/ogrenifloader.hpp | 18 ++++++++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 686fbbb848..f3ecbd6a51 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,6 +78,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -89,6 +90,19 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } + const NifOgre::ObjectList &objects = mAnimationSources.back(); + + for(size_t i = 0;i < objects.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!skelinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = skelinst->getBone(trgtname); + dstval->setNode(bone); + } Ogre::Entity *ent = mAnimationSources.back().mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d02c0816e3..a0aefaccc9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -108,10 +108,9 @@ public: class VisController { public: - class Value : public Ogre::ControllerValue + class Value : public NodeTargetValue { private: - Ogre::Bone *mTarget; std::vector mData; virtual bool calculate(Ogre::Real time) @@ -149,8 +148,8 @@ public: } public: - Value(Ogre::Bone *target, const Nif::NiVisData *data) - : mTarget(target) + Value(Ogre::Node *target, const Nif::NiVisData *data) + : NodeTargetValue(target) , mData(data->mVis) { } @@ -163,7 +162,7 @@ public: virtual void setValue(Ogre::Real time) { bool vis = calculate(time); - setVisible(mTarget, vis); + setVisible(mNode, vis); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 3a7a22f8b1..18bbf0200f 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -74,6 +74,24 @@ public: const std::string &group="General"); }; +// FIXME: Should be with other general Ogre extensions. +template +class NodeTargetValue : public Ogre::ControllerValue +{ +protected: + Ogre::Node *mNode; + +public: + NodeTargetValue(Ogre::Node *target) : mNode(target) + { } + + void setNode(Ogre::Node *target) + { mNode = target; } + Ogre::Node *getNode() const + { return mNode; } +}; +typedef Ogre::SharedPtr > NodeTargetValueRealPtr; + } namespace std From 43a501369080f633f829a4b3e64e87b960d738ec Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 7 Apr 2013 23:25:35 +0200 Subject: [PATCH 0347/1537] added verifier for birthsign record --- apps/opencs/CMakeLists.txt | 1 + apps/opencs/model/tools/birthsigncheck.cpp | 39 ++++++++++++++++++++++ apps/opencs/model/tools/birthsigncheck.hpp | 29 ++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 ++ 4 files changed, 72 insertions(+) create mode 100644 apps/opencs/model/tools/birthsigncheck.cpp create mode 100644 apps/opencs/model/tools/birthsigncheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 301febfc49..87221d7af5 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -36,6 +36,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck + birthsigncheck ) diff --git a/apps/opencs/model/tools/birthsigncheck.cpp b/apps/opencs/model/tools/birthsigncheck.cpp new file mode 100644 index 0000000000..b673c93ded --- /dev/null +++ b/apps/opencs/model/tools/birthsigncheck.cpp @@ -0,0 +1,39 @@ + +#include "birthsigncheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::BirthsignCheckStage::BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns) +: mBirthsigns (birthsigns) +{} + +int CSMTools::BirthsignCheckStage::setup() +{ + return mBirthsigns.getSize(); +} + +void CSMTools::BirthsignCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::BirthSign& birthsign = mBirthsigns.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Birthsign, birthsign.mId); + + // test for empty name, description and texture + if (birthsign.mName.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name"); + + if (birthsign.mDescription.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description"); + + if (birthsign.mTexture.empty()) + messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture"); + + /// \todo test if the texture exists + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/birthsigncheck.hpp b/apps/opencs/model/tools/birthsigncheck.hpp new file mode 100644 index 0000000000..42b5a6b244 --- /dev/null +++ b/apps/opencs/model/tools/birthsigncheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_BIRTHSIGNCHECK_H +#define CSM_TOOLS_BIRTHSIGNCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that birthsign records are internally consistent + class BirthsignCheckStage : public Stage + { + const CSMWorld::IdCollection& mBirthsigns; + + public: + + BirthsignCheckStage (const CSMWorld::IdCollection& birthsigns); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 45adcf5e49..78796de418 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -18,6 +18,7 @@ #include "racecheck.hpp" #include "soundcheck.hpp" #include "regioncheck.hpp" +#include "birthsigncheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -69,6 +70,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new SoundCheckStage (mData.getSounds())); mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); + + mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); } return mVerifier; From 261ea1fe5e137386e4b859bcbae6b519d4fa3b1f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 14:56:23 -0700 Subject: [PATCH 0348/1537] Implement a KeyframeController --- apps/openmw/mwrender/animation.cpp | 21 ++++-- apps/openmw/mwrender/animation.hpp | 1 + components/nifogre/ogrenifloader.cpp | 107 +++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f3ecbd6a51..fd7aeac1d0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -37,6 +37,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) , mLastPosition(0.0f) + , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentAnim(NULL) , mCurrentTime(0.0f) @@ -68,6 +69,7 @@ void Animation::setAnimationSources(const std::vector &names) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + mCurrentControllers = &mObjectList.mControllers; mCurrentAnim = NULL; mCurrentKeys = NULL; mAnimVelocity = 0.0f; @@ -78,6 +80,7 @@ void Animation::setAnimationSources(const std::vector &names) destroyObjectList(sceneMgr, mAnimationSources[i]); mAnimationSources.clear(); + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) @@ -90,7 +93,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.pop_back(); continue; } - const NifOgre::ObjectList &objects = mAnimationSources.back(); + NifOgre::ObjectList &objects = mAnimationSources.back(); for(size_t i = 0;i < objects.mControllers.size();i++) { @@ -104,7 +107,13 @@ void Animation::setAnimationSources(const std::vector &names) dstval->setNode(bone); } - Ogre::Entity *ent = mAnimationSources.back().mSkelBase; + for(size_t i = 0;i < objects.mControllers.size();i++) + { + if(objects.mControllers[i].getSource().isNull()) + objects.mControllers[i].setSource(ctrlval); + } + + Ogre::Entity *ent = objects.mSkelBase; Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -167,6 +176,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model if(mObjectList.mControllers[i].getSource().isNull()) mObjectList.mControllers[i].setSource(ctrlval); } + mCurrentControllers = &mObjectList.mControllers; } @@ -441,12 +451,13 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::const_reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; if(mNonAccumRoot) @@ -495,8 +506,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mObjectList.mControllers.size();i++) - mObjectList.mControllers[i].update(); + for(size_t i = 0;i < mCurrentControllers->size();i++) + (*mCurrentControllers)[i].update(); return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 22ab9fc7eb..aee139bd67 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -49,6 +49,7 @@ protected: std::vector mAnimationSources; + std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; Ogre::Animation *mCurrentAnim; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a0aefaccc9..e7bf820b8e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -169,6 +169,101 @@ public: typedef DefaultFunction Function; }; +class KeyframeController +{ +public: + class Value : public NodeTargetValue + { + private: + Nif::QuaternionKeyList mRotations; + Nif::Vector3KeyList mTranslations; + Nif::FloatKeyList mScales; + + public: + Value(Ogre::Node *target, const Nif::NiKeyframeData *data) + : NodeTargetValue(target) + , mRotations(data->mRotations) + , mTranslations(data->mTranslations) + , mScales(data->mScales) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real time) + { + if(mRotations.mKeys.size() > 0) + { + if(time <= mRotations.mKeys.front().mTime) + mNode->setOrientation(mRotations.mKeys.front().mValue); + else if(time >= mRotations.mKeys.back().mTime) + mNode->setOrientation(mRotations.mKeys.back().mValue); + else + { + Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); + for(;iter != mRotations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); + break; + } + } + } + if(mTranslations.mKeys.size() > 0) + { + if(time <= mTranslations.mKeys.front().mTime) + mNode->setPosition(mTranslations.mKeys.front().mValue); + else if(time >= mTranslations.mKeys.back().mTime) + mNode->setPosition(mTranslations.mKeys.back().mValue); + else + { + Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); + for(;iter != mTranslations.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); + break; + } + } + } + if(mScales.mKeys.size() > 0) + { + if(time <= mScales.mKeys.front().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); + else if(time >= mScales.mKeys.back().mTime) + mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); + else + { + Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); + for(;iter != mScales.mKeys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); + break; + } + } + } + } + }; + + typedef DefaultFunction Function; +}; + class UVController { public: @@ -1546,6 +1641,18 @@ class NIFObjectLoader : Ogre::ManualResourceLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } From 3c633e275e99852ea48e8b8e1e49f3145c63e640 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 15:42:07 -0700 Subject: [PATCH 0349/1537] Don't create a controller for empty keyframe data --- components/nifogre/ogrenifloader.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e7bf820b8e..e06a23b5b9 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1644,14 +1644,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader else if(ctrl->recType == Nif::RC_NiKeyframeController) { const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } } ctrl = ctrl->next; } From 7baca30a1d10bd0cef7b49e59be39e7df92692e2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 16:21:45 -0700 Subject: [PATCH 0350/1537] Only get the non-accum root's keyframe when updating positions The actual animation pose is now handled by the controllers, based on the current animation time. --- apps/openmw/mwrender/animation.cpp | 80 ++++++++++++++---------------- apps/openmw/mwrender/animation.hpp | 9 ++-- 2 files changed, 40 insertions(+), 49 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fd7aeac1d0..72f7ebaf2e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -263,28 +263,6 @@ void Animation::calcAnimVelocity() } } -void Animation::applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel) -{ - Ogre::TimeIndex timeindex = anim->_getTimeIndex(time); - Ogre::Animation::NodeTrackIterator tracks = anim->getNodeTrackIterator(); - while(tracks.hasMoreElements()) - { - Ogre::NodeAnimationTrack *track = tracks.getNext(); - const Ogre::String &targetname = track->getAssociatedNode()->getName(); - if(!skel->hasBone(targetname)) - continue; - Ogre::Bone *bone = skel->getBone(targetname); - bone->setOrientation(Ogre::Quaternion::IDENTITY); - bone->setPosition(Ogre::Vector3::ZERO); - bone->setScale(Ogre::Vector3::UNIT_SCALE); - track->applyToNode(bone, timeindex); - } - - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); -} - static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) { if(skelsrc->hasBone(bone->getName())) @@ -323,24 +301,29 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition(float time) +Ogre::Vector3 Animation::updatePosition() { - if(mLooping) - mCurrentTime = std::fmod(std::max(time, 0.0f), mCurrentAnim->getLength()); - else - mCurrentTime = std::min(mCurrentAnim->getLength(), std::max(time, 0.0f)); - applyAnimation(mCurrentAnim, mCurrentTime, mObjectList.mSkelBase->getSkeleton()); + Ogre::Vector3 posdiff; - Ogre::Vector3 posdiff = Ogre::Vector3::ZERO; - if(mNonAccumRoot) + Ogre::TransformKeyFrame kf(0, mCurrentTime); + Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + while(trackiter.hasMoreElements()) { - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumRoot->getPosition() - mLastPosition) * mAccumulate; - - /* Translate the accumulation root back to compensate for the move. */ - mLastPosition += posdiff; - mAccumRoot->setPosition(-mLastPosition); + const Ogre::NodeAnimationTrack *track = trackiter.getNext(); + if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + { + track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); + break; + } } + + /* Get the non-accumulation root's difference from the last update. */ + posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + + /* Translate the accumulation root back to compensate for the move. */ + mLastPosition += posdiff; + mAccumRoot->setPosition(-mLastPosition); + return posdiff; } @@ -486,11 +469,14 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) timepassed *= mAnimSpeedMult; while(mCurrentAnim && mPlaying) { - float targetTime = std::min(mStopTime, mCurrentTime+timepassed); + float targetTime = mCurrentTime + timepassed; if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) { - movement += updatePosition(targetTime); - mPlaying = (mLooping || mStopTime > targetTime); + mCurrentTime = std::min(mStopTime, targetTime); + if(mNonAccumRoot) + movement += updatePosition(); + mPlaying = (mLooping || mStopTime > mCurrentTime); + timepassed = targetTime - mCurrentTime; break; } @@ -498,10 +484,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) const std::string &evt = mNextKey->second; mNextKey++; - movement += updatePosition(time); - mPlaying = (mLooping || mStopTime > time); - - timepassed = targetTime - time; + mCurrentTime = time; + if(mNonAccumRoot) + movement += updatePosition(); + mPlaying = (mLooping || mStopTime > mCurrentTime); + timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) break; @@ -509,6 +496,13 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); + if(mObjectList.mSkelBase) + { + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index aee139bd67..2fcc1e8f70 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -63,16 +63,13 @@ protected: void calcAnimVelocity(); - /* Applies the given animation to the given skeleton instance, using the specified time. */ - void applyAnimation(const Ogre::Animation *anim, float time, Ogre::SkeletonInstance *skel); - /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ void updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Ogre::SkeletonInstance *skel); - /* Updates the animation to the specified time, and returns the movement - * vector since the last update or reset. */ - Ogre::Vector3 updatePosition(float time); + /* Updates the position of the accum root node for the current time, and + * returns the wanted movement vector from the previous update. */ + Ogre::Vector3 updatePosition(); /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If From dba7308248ef270a5a138c2f0470b9412e13e414 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 17:16:49 -0700 Subject: [PATCH 0351/1537] Recognize NiParticleRotation --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e06a23b5b9..ac1e8e056e 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1487,13 +1487,17 @@ class NIFObjectLoader : Ogre::ManualResourceLoader affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } + else if(e->recType == Nif::RC_NiParticleRotation) + { + // TODO: Implement (Ogre::RotationAffector?) + } else if(e->recType == Nif::RC_NiParticleColorModifier) { // TODO: Implement (Ogre::ColourInterpolatorAffector?) } else if(e->recType == Nif::RC_NiGravity) { - // TODO: Implement (Ogre::LinearForceAffector?) + // TODO: Implement } else warn("Unhandled particle modifier "+e->recName); From c6c67a1bb49d22d93f6c9f6bf5859ddc4c5629f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 7 Apr 2013 18:15:23 -0700 Subject: [PATCH 0352/1537] Read NiGravity fields --- components/nif/controlled.hpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/nif/controlled.hpp b/components/nif/controlled.hpp index 08c47defee..6acb8ff201 100644 --- a/components/nif/controlled.hpp +++ b/components/nif/controlled.hpp @@ -98,12 +98,23 @@ public: class NiGravity : public Controlled { public: + float mForce; + /* 0 - Wind (fixed direction) + * 1 - Point (fixed origin) + */ + int mType; + Ogre::Vector3 mPosition; + Ogre::Vector3 mDirection; + void read(NIFStream *nif) { Controlled::read(nif); - // two floats, one int, six floats - nif->skip(9*4); + /*unknown*/nif->getFloat(); + mForce = nif->getFloat(); + mType = nif->getUInt(); + mPosition = nif->getVector3(); + mDirection = nif->getVector3(); } }; From 08d43fe21787501b5a572c946268e8e2874b2410 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 05:48:52 -0700 Subject: [PATCH 0353/1537] Make the getHeadNode method more general --- apps/openmw/mwrender/animation.cpp | 12 ++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 5 ----- apps/openmw/mwrender/npcanimation.hpp | 2 -- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 72f7ebaf2e..067e856720 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -180,6 +180,18 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model } +Ogre::Node *Animation::getNode(const std::string &name) +{ + if(mObjectList.mSkelBase) + { + Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + if(skel->hasBone(name)) + return skel->getBone(name); + } + return NULL; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 2fcc1e8f70..cfef28f16c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -113,6 +113,8 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); + + Ogre::Node *getNode(const std::string &name); }; } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 843bcf007b..616543a7d4 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -201,7 +201,7 @@ namespace MWRender void RaceSelectionPreview::updateCamera() { Ogre::Vector3 scale = mNode->getScale(); - Ogre::Vector3 headOffset = mAnimation->getHeadNode()->_getDerivedPosition(); + Ogre::Vector3 headOffset = mAnimation->getNode("Bip01 Head")->_getDerivedPosition(); headOffset = mNode->convertLocalToWorldPosition(headOffset); mCamera->setPosition(headOffset + mPosition * scale); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 253dbb0ff7..d7620a8de5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -451,9 +451,4 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorgetSkeleton()->getBone("Bip01 Head"); -} - } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index b59051a8d6..224d174f43 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -78,8 +78,6 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); - Ogre::Node* getHeadNode(); - void forceUpdate() { updateParts(true); } }; From a5c868c9f58c26210da7f818fd4449acb7a9a7e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 14:54:19 +0200 Subject: [PATCH 0354/1537] Create a separate vertex buffer for each UV set --- components/nifogre/ogrenifloader.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8f9d69f6e2..a94f469010 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -992,17 +992,19 @@ class NIFMeshLoader : Ogre::ManualResourceLoader size_t numUVs = data->uvlist.size(); if(numUVs) { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size()*numUVs, - Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY, true); for(size_t i = 0;i < numUVs;i++) { + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + const std::vector &uvlist = data->uvlist[i]; - vbuf->writeData(i*srcVerts.size()*elemSize, elemSize*srcVerts.size(), &uvlist[0], true); - decl->addElement(nextBuf, i*srcVerts.size()*elemSize, Ogre::VET_FLOAT2, + + vbuf->writeData(0, elemSize*srcVerts.size(), &uvlist[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); } - bind->setBinding(nextBuf++, vbuf); } // Triangle faces From 343e2027af0797db178967ca36765d26373ac138 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 15:17:30 +0200 Subject: [PATCH 0355/1537] Support NIF detail maps --- components/nifogre/ogrenifloader.cpp | 15 ++++++++++++++- files/materials/objects.mat | 16 +++++++++++++--- files/materials/objects.shader | 17 +++++++++++++++-- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a94f469010..9244ac6ccc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -749,16 +749,29 @@ static Ogre::String getMaterial(const Nif::NiTriShape *shape, const Ogre::String instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) { instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); } + if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) + { + instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) + { + // force automips on normal maps for now + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); + } + for(int i = 1;i < 7;i++) { - if(!texName[i].empty()) + if(!texName[i].empty() && (i == Nif::NiTexturingProperty::DarkTexture || i == Nif::NiTexturingProperty::DecalTexture + || i == Nif::NiTexturingProperty::GlossTexture)) warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)+"\n"); } diff --git a/files/materials/objects.mat b/files/materials/objects.mat index 49df4e3949..994a18ea94 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -9,9 +9,10 @@ material openmw_objects_base normalMap emissiveMap use_emissive_map false + use_detail_map false emissiveMapUVSet 0 + detailMapUVSet 0 - is_transparent false // real transparency, alpha rejection doesn't count here scene_blend default depth_write default depth_check default @@ -26,10 +27,11 @@ material openmw_objects_base shader_properties { vertexcolor_mode $vertmode - is_transparent $is_transparent normalMap $normalMap emissiveMapUVSet $emissiveMapUVSet + detailMapUVSet $detailMapUVSet emissiveMap $emissiveMap + detailMap $detailMap } diffuse $diffuse @@ -51,7 +53,7 @@ material openmw_objects_base texture_unit normalMap { - direct_texture $normalMap + texture $normalMap } texture_unit emissiveMap @@ -61,6 +63,14 @@ material openmw_objects_base direct_texture $emissiveMap tex_coord_set $emissiveMapUVSet } + + texture_unit detailMap + { + create_in_ffp $use_detail_map + colour_op_ex modulate_x2 src_current src_texture + direct_texture $detailMap + tex_coord_set $detailMapUVSet + } texture_unit shadowMap0 { diff --git a/files/materials/objects.shader b/files/materials/objects.shader index d0e8173733..aa7f006a22 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -16,9 +16,10 @@ #define NORMAL_MAP @shPropertyHasValue(normalMap) #define EMISSIVE_MAP @shPropertyHasValue(emissiveMap) +#define DETAIL_MAP @shPropertyHasValue(detailMap) // right now we support 2 UV sets max. implementing them is tedious, and we're probably not going to need more -#define SECOND_UV_SET @shPropertyString(emissiveMapUVSet) +#define SECOND_UV_SET (@shPropertyString(emissiveMapUVSet) || @shPropertyString(detailMapUVSet)) // if normal mapping is enabled, we force pixel lighting #define VERTEX_LIGHTING (!@shPropertyHasValue(normalMap)) @@ -236,6 +237,10 @@ shSampler2D(emissiveMap) #endif +#if DETAIL_MAP + shSampler2D(detailMap) +#endif + shInput(float4, UV) #if NORMAL_MAP @@ -313,6 +318,14 @@ { shOutputColour(0) = shSample(diffuseMap, UV.xy); +#if DETAIL_MAP +#if @shPropertyString(detailMapUVSet) + shOutputColour(0) *= shSample(detailMap, UV.zw)*2; +#else + shOutputColour(0) *= shSample(detailMap, UV.xy)*2; +#endif +#endif + #if NORMAL_MAP float3 normal = normalPassthrough; float3 binormal = cross(tangentPassthrough.xyz, normal.xyz); @@ -419,7 +432,7 @@ #endif #if EMISSIVE_MAP - #if SECOND_UV_SET + #if @shPropertyString(emissiveMapUVSet) shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz; #else shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz; From a7de870a443bb602ea45515f312ed730f46045b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 16:21:18 +0200 Subject: [PATCH 0356/1537] Fix mercenary not updating its profit when item was dragged onto the player avatar --- apps/openmw/mwgui/inventorywindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 001f42bd11..c744fcf6d9 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -150,6 +150,7 @@ namespace MWGui it = invStore.add(ptr); (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); ptr = *it; + mDragAndDrop->mDraggedFrom->notifyItemDragged(ptr, -mDragAndDrop->mDraggedCount); } /// \todo scripts From d0bcf830919ec034f40f213404be618bc588fefc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 8 Apr 2013 16:30:18 +0200 Subject: [PATCH 0357/1537] Adjust player position to ground after using travel services --- apps/openmw/mwgui/travelwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 465f588b8a..2508498fa0 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -156,6 +156,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->advanceTime(time); } MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); + MWWorld::Class::get(player).adjustPosition(player); mWindowManager.removeGuiMode(GM_Travel); mWindowManager.removeGuiMode(GM_Dialogue); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); From 50932a7a6bf52281aaa37242e53d0d84739a80ac Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 17:50:03 +0200 Subject: [PATCH 0358/1537] Finished bugfix #691 --- apps/openmw/mwclass/armor.cpp | 47 ++++++++++++++------------------ apps/openmw/mwclass/clothing.cpp | 31 ++++++++++++--------- apps/openmw/mwclass/weapon.cpp | 42 +++++++--------------------- 3 files changed, 49 insertions(+), 71 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 496e695450..f6392941d6 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -321,15 +321,10 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = it->get()->mBase->mParts.mParts; + if(*slot == MWWorld::InventoryStore::Slot_Helmet) { - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; - - bool allow = true; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_Head) @@ -337,41 +332,41 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - allow = false; - break; + return false; } } - - if(!allow) - break; } if (*slot == MWWorld::InventoryStore::Slot_Boots) { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - allow = false; - // Only notify the player, not npcs if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - } - break; + return false; } } - - if(!allow) - return false; } + } + if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) + { + MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + { + //unequip twohanded item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + return true; } } return true; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 77a7557bf6..318515a7b1 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -267,32 +267,37 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { + std::vector parts = it->get()->mBase->mParts.mParts; + + if(*slot == MWWorld::InventoryStore::Slot_Helmet) + { + for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) + { + if((*itr).mPart == ESM::PRT_Head) + { + if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); + + return false; + } + } + } + if (*slot == MWWorld::InventoryStore::Slot_Boots) { - bool allow = true; - std::vector parts; - if(it.getType() == MWWorld::ContainerStore::Type_Clothing) - parts = it->get()->mBase->mParts.mParts; - else - parts = it->get()->mBase->mParts.mParts; for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - allow = false; - // Only notify the player, not npcs if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } - break; + + return false; } } - - if(!allow) - return false; } - } } return true; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 51e8130039..a0a8b7e874 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -411,41 +411,19 @@ namespace MWClass { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if (it.getType() == MWWorld::ContainerStore::Type_Weapon) + if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - } - } - } - if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft) - { - MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - - if (weapon.getType() == MWWorld::ContainerStore::Type_Weapon) - { - if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - weapon->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) - { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } + //unequip lefthand item + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); } + return true; } - return true; } return false; } From 194ca2584dfced9e807c1c5865eb3b5600a723e0 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 17:53:41 +0200 Subject: [PATCH 0359/1537] Small azura's star fix --- apps/openmw/mwmechanics/enchanting.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/enchanting.cpp b/apps/openmw/mwmechanics/enchanting.cpp index d92acdafc0..a38cb0037b 100644 --- a/apps/openmw/mwmechanics/enchanting.cpp +++ b/apps/openmw/mwmechanics/enchanting.cpp @@ -53,14 +53,18 @@ namespace MWMechanics bool Enchanting::create() { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); ESM::Enchantment enchantment; enchantment.mData.mCharge = getGemCharge(); - //Exception for Azura Star, it's not destroyed after enchanting + mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + + //Exception for Azura Star, new one will be added after enchanting if(boost::iequals(mSoulGemPtr.get()->mBase->mId, "Misc_SoulGem_Azura")) - mSoulGemPtr.getCellRef().mSoul=""; - else - mSoulGemPtr.getRefData().setCount (mSoulGemPtr.getRefData().getCount()-1); + { + MWWorld::ManualRef azura (MWBase::Environment::get().getWorld()->getStore(), "Misc_SoulGem_Azura"); + MWWorld::Class::get (player).getContainerStore (player).add (azura.getPtr()); + } if(mSelfEnchanting) { @@ -87,7 +91,6 @@ namespace MWMechanics MWWorld::ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), mOldItemId); ref.getPtr().getRefData().setCount (mOldItemCount-1); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWWorld::Class::get (player).getContainerStore (player).add (ref.getPtr()); if(!mSelfEnchanting) payForEnchantment(); From 23097ac9dc3b0046471bb1ebce1238dc5a97af61 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 09:47:03 -0700 Subject: [PATCH 0360/1537] Minor cleanup of NiMorphData --- components/nif/data.hpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index 0804b53ae2..bd109041f1 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -398,16 +398,13 @@ struct NiMorphData : public Record { int morphCount = nif->getInt(); int vertCount = nif->getInt(); - nif->getChar(); + /*relative targets?*/nif->getChar(); mMorphs.resize(morphCount); for(int i = 0;i < morphCount;i++) { mMorphs[i].mData.read(nif, true); - - mMorphs[i].mVertices.resize(vertCount); - for(int j = 0;j < vertCount;j++) - mMorphs[i].mVertices[j] = nif->getVector3(); + nif->getVector3s(mMorphs[i].mVertices, vertCount); } } }; From 2f52df22cea1558074457146f67b8e22516e5976 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 19:00:38 +0200 Subject: [PATCH 0361/1537] Bugfix #553 --- apps/openmw/mwgui/journalwindow.cpp | 6 ------ apps/openmw/mwgui/journalwindow.hpp | 1 - apps/openmw/mwinput/inputmanagerimp.cpp | 6 ++++++ 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ba39b01012..f33cfd353f 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -114,15 +114,9 @@ MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) //displayLeftText(list.front()); } -void MWGui::JournalWindow::close() -{ - MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); -} - void MWGui::JournalWindow::open() { mPageNumber = 0; - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { book journal; diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cd1ff7ebbd..f68cca46e9 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -16,7 +16,6 @@ namespace MWGui public: JournalWindow(MWBase::WindowManager& parWindowManager); virtual void open(); - virtual void close(); private: void displayLeftText(std::string text); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 0ed49cd7f7..c23106be1a 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -656,9 +656,15 @@ namespace MWInput bool gameMode = !mWindows.isGuiMode(); if(gameMode) + { + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); mWindows.pushGuiMode(MWGui::GM_Journal); + } else if(mWindows.getMode() == MWGui::GM_Journal) + { + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); mWindows.popGuiMode(); + } // .. but don't touch any other mode. } From 7c22e123f4c6fb37f27f874749096a4b9a8b4558 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 8 Apr 2013 22:10:55 +0200 Subject: [PATCH 0362/1537] Bugfix #691 changes --- apps/openmw/mwclass/armor.cpp | 27 +++++------------ apps/openmw/mwclass/armor.hpp | 3 +- apps/openmw/mwclass/clothing.cpp | 24 ++++------------ apps/openmw/mwclass/clothing.hpp | 3 +- apps/openmw/mwclass/weapon.cpp | 40 +++++++------------------- apps/openmw/mwclass/weapon.hpp | 3 +- apps/openmw/mwworld/actionequip.cpp | 11 +++++-- apps/openmw/mwworld/class.cpp | 4 +-- apps/openmw/mwworld/class.hpp | 4 +-- apps/openmw/mwworld/inventorystore.cpp | 13 +++++++-- 10 files changed, 53 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index f6392941d6..ddab6f7548 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,25 +292,13 @@ namespace MWClass ref->mBase = record; } - bool Armor::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Armor::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - std::string npcRace = npc.get()->mBase->mRace; for (std::vector::const_iterator slot=slots.first.begin(); @@ -321,7 +309,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = it->get()->mBase->mParts.mParts; + std::vector parts = item.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { @@ -332,7 +320,7 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - return false; + return 0; } } } @@ -345,7 +333,7 @@ namespace MWClass { if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - return false; + return 0; } } } @@ -363,13 +351,12 @@ namespace MWClass weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - //unequip twohanded item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + return 3; } - return true; + return 1; } } - return true; + return 1; } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index bb07e42b03..96c72848cc 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 318515a7b1..58c4a2c5c6 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,25 +238,11 @@ namespace MWClass ref->mBase = record; } - bool Clothing::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Clothing::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); - // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - std::string npcRace = npc.get()->mBase->mRace; for (std::vector::const_iterator slot=slots.first.begin(); @@ -267,7 +253,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = it->get()->mBase->mParts.mParts; + std::vector parts = item.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { @@ -278,7 +264,7 @@ namespace MWClass if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - return false; + return 0; } } } @@ -294,13 +280,13 @@ namespace MWClass MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); } - return false; + return 0; } } } } } - return true; + return 1; } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 4978fa2288..eb8d801996 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a0a8b7e874..a0cacaf6bd 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,48 +384,30 @@ namespace MWClass ref->mBase = record; } - bool Weapon::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Weapon::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); - - // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); - // retrieve ContainerStoreIterator to the item - MWWorld::ContainerStoreIterator it = invStore.begin(); - for (; it != invStore.end(); ++it) - { - if (*it == item) - { - break; - } - } - - assert(it != invStore.end()); - - std::string npcRace = npc.get()->mBase->mRace; - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if(it->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - it->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - it->get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - it->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if(item.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + item.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + item.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - //unequip lefthand item - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + return 2; } - return true; + return 1; } } - return false; + return 0; } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 922cd165f2..01686b09cc 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,7 +67,8 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index c147113fc6..51d0de6fe8 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,8 +43,15 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - if(!MWWorld::Class::get(getTarget()).canEquip(actor,getTarget())) - break; + switch(MWWorld::Class::get (*it).canBeEquipped (actor, *it)) + { + case 0: + return; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index ee2072cf09..a0067f5d2e 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,9 +259,9 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - bool Class::canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Class::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const { - return true; + return 1; } void Class::adjustPosition(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 4931da7a86..362a8bc9ca 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,8 +242,8 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual bool canEquip(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; - ///< Return 0 if player cannot equip item. Unequip twohanded item if neccesary + virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 7a5ae38d0e..9f51db3534 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -131,6 +131,8 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSlot (int slot) void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) { const MWMechanics::NpcStats& stats = MWWorld::Class::get(npc).getNpcStats(npc); + MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); + TSlots slots; initSlots (slots); @@ -184,8 +186,15 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - if(!MWWorld::Class::get (test).canEquip (npc, test)) - continue; + switch(MWWorld::Class::get (test).canBeEquipped (npc, test)) + { + case 0: + continue; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped { From e7c0f2a211b4854b6ce6198c5245a6071483b0da Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 14:54:13 -0700 Subject: [PATCH 0363/1537] Minor cleanup to loading texture UV coords --- components/nifogre/ogrenifloader.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index aa28a30dd2..bf4621e6f0 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1400,21 +1400,14 @@ class NIFObjectLoader : Ogre::ManualResourceLoader // Texture UV coordinates size_t numUVs = data->uvlist.size(); - if(numUVs) + for(size_t i = 0;i < numUVs;i++) { - for(size_t i = 0;i < numUVs;i++) - { - size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); - vbuf = hwBufMgr->createVertexBuffer(elemSize, srcVerts.size(), - Ogre::HardwareBuffer::HBU_STATIC); + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), + srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); - const std::vector &uvlist = data->uvlist[i]; - - vbuf->writeData(0, elemSize*srcVerts.size(), &uvlist[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, - Ogre::VES_TEXTURE_COORDINATES, i); - bind->setBinding(nextBuf++, vbuf); - } + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); } // Triangle faces From 973fdeb2e01be028de7e5fa0b3df473c72fce397 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 8 Apr 2013 15:21:28 -0700 Subject: [PATCH 0364/1537] Improve particle system placement when no emitters are specified --- components/nifogre/ogrenifloader.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index bf4621e6f0..3c876283e1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1566,7 +1566,11 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } if(!partsys->isAttached()) - entitybase->attachObjectToBone(partnode->name, partsys); + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partnode->recIndex); + Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); + entitybase->attachObjectToBone(trgtbone->getName(), partsys); + } } catch(std::exception &e) { std::cerr<< "Particles exception: "< Date: Tue, 9 Apr 2013 01:24:17 +0200 Subject: [PATCH 0365/1537] Fix several NPCs spawning in the ground --- apps/openmw/mwworld/scene.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2244a4fc64..439f761311 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -118,6 +118,7 @@ namespace MWWorld float verts = ESM::Land::LAND_SIZE; float worldsize = ESM::Land::REAL_SIZE; + // Load terrain physics first... if (cell->mCell->isExterior()) { ESM::Land* land = @@ -137,6 +138,7 @@ namespace MWWorld } } + // ... then references. This is important for adjustPosition to work correctly. /// \todo rescale depending on the state of a new GMST insertCell (*cell, true); @@ -439,7 +441,6 @@ namespace MWWorld insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale); - insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale); @@ -447,11 +448,13 @@ namespace MWWorld insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale); - insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale); insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale); + // Load NPCs and creatures _after_ everything else (important for adjustPosition to work correctly) + insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale); + insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale); } void Scene::addObjectToScene (const Ptr& ptr) From 623c2c8201c80857bbaefe4278b04e88cdda269b Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 07:45:07 +0200 Subject: [PATCH 0366/1537] Minor fix --- apps/openmw/mwworld/actionequip.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 51d0de6fe8..d5927b6c55 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,7 +43,7 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (*it).canBeEquipped (actor, *it)) + switch(MWWorld::Class::get (getTarget()).canBeEquipped (actor, getTarget())) { case 0: return; From ec6dff38b187691b809c4b90ac15c27a972d4da2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 11:40:36 +0200 Subject: [PATCH 0367/1537] added basic spell table --- apps/opencs/model/world/data.cpp | 19 +++++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadspel.cpp | 10 ++++++++++ components/esm/loadspel.hpp | 3 +++ 9 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index b385c5b4c2..af2b17bd96 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -99,6 +99,13 @@ CSMWorld::Data::Data() mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); + mSpells.addColumn (new StringIdColumn); + mSpells.addColumn (new RecordStateColumn); + mSpells.addColumn (new NameColumn); + mSpells.addColumn (new FlagColumn ("Autocalc", 0x1)); + mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); + mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -109,6 +116,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); + addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); } CSMWorld::Data::~Data() @@ -217,6 +225,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getBirthsigns() return mBirthsigns; } +const CSMWorld::IdCollection& CSMWorld::Data::getSpells() const +{ + return mSpells; +} + +CSMWorld::IdCollection& CSMWorld::Data::getSpells() +{ + return mSpells; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -261,6 +279,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; + case ESM::REC_SPEL: mSpells.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 122e855d86..d7b69ba5e3 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "idcollection.hpp" #include "universalid.hpp" @@ -36,6 +37,7 @@ namespace CSMWorld IdCollection mScripts; IdCollection mRegions; IdCollection mBirthsigns; + IdCollection mSpells; std::vector mModels; std::map mModelIndex; @@ -92,6 +94,10 @@ namespace CSMWorld IdCollection& getBirthsigns(); + const IdCollection& getSpells() const; + + IdCollection& getSpells(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 6d305d6c0f..11f4877886 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -27,6 +27,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -43,6 +44,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 0586719f14..5586b22e79 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -53,7 +53,9 @@ namespace CSMWorld Type_Regions, Type_Region, Type_Birthsigns, - Type_Birthsign + Type_Birthsign, + Type_Spells, + Type_Spell }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index af9b814203..dfdcb10365 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -121,6 +121,10 @@ void CSVDoc::View::setupWorldMenu() QAction *birthsigns = new QAction (tr ("Birthsigns"), this); connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView())); world->addAction (birthsigns); + + QAction *spells = new QAction (tr ("Spells"), this); + connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); + world->addAction (spells); } void CSVDoc::View::setupUi() @@ -316,6 +320,11 @@ void CSVDoc::View::addBirthsignsSubView() addSubView (CSMWorld::UniversalId::Type_Birthsigns); } +void CSVDoc::View::addSpellsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Spells); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 12944e5693..9241efbb9a 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -131,6 +131,8 @@ namespace CSVDoc void addRegionsSubView(); void addBirthsignsSubView(); + + void addSpellsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 23c66319c6..c9ef4df8db 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -24,6 +24,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, + CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp index b0f1ca64b9..8149fe4cef 100644 --- a/components/esm/loadspel.cpp +++ b/components/esm/loadspel.cpp @@ -20,4 +20,14 @@ void Spell::save(ESMWriter &esm) mEffects.save(esm); } + void Spell::blank() + { + mData.mType = 0; + mData.mCost = 0; + mData.mFlags = 0; + + mName.clear(); + + mEffects.mList.clear(); + } } diff --git a/components/esm/loadspel.hpp b/components/esm/loadspel.hpp index 0d5e0be522..3a620962d1 100644 --- a/components/esm/loadspel.hpp +++ b/components/esm/loadspel.hpp @@ -43,6 +43,9 @@ struct Spell void load(ESMReader &esm); void save(ESMWriter &esm); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From ae0a7d5bcde2e15b228b388f9e693b1453378a36 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 11:53:47 +0200 Subject: [PATCH 0368/1537] added cost and type columns to spell table --- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 48 ++++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 2 ++ apps/opencs/view/doc/viewmanager.cpp | 8 +++++ 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 5c2ce8a676..23049164f8 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -34,7 +34,8 @@ namespace CSMWorld Display_GlobalVarType, Display_Specialisation, Display_Attribute, - Display_Boolean + Display_Boolean, + Display_SpellType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index fbc533779a..6d6d1b1ef0 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -675,6 +675,54 @@ namespace CSMWorld return true; } }; + + template + struct SpellTypeColumn : public Column + { + SpellTypeColumn() : Column ("Type", ColumnBase::Display_SpellType) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mType; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mData.mType = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; + + template + struct CostColumn : public Column + { + CostColumn() : Column ("Cost", ColumnBase::Display_Integer) {} + + virtual QVariant get (const Record& record) const + { + return record.get().mData.mCost; + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + record2.mData.mCost = data.toInt(); + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index af2b17bd96..84b49b6bcd 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -102,6 +102,8 @@ CSMWorld::Data::Data() mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); mSpells.addColumn (new NameColumn); + mSpells.addColumn (new SpellTypeColumn); + mSpells.addColumn (new CostColumn); mSpells.addColumn (new FlagColumn ("Autocalc", 0x1)); mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 3be7228b31..050bd51fe2 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -49,6 +49,11 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) "Luck", 0 }; + static const char *sSpellTypes[] = + { + "Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0 + }; + mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, @@ -62,6 +67,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute, new CSVWorld::EnumDelegateFactory (sAttributes, true)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType, + new CSVWorld::EnumDelegateFactory (sSpellTypes)); } CSVDoc::ViewManager::~ViewManager() From 40bb772e34aedf01c472aad93147c3a81a5a983d Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 12:44:49 +0200 Subject: [PATCH 0369/1537] added verifier for spell record --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/tools/spellcheck.cpp | 35 ++++++++++++++++++++++++++ apps/opencs/model/tools/spellcheck.hpp | 29 +++++++++++++++++++++ apps/opencs/model/tools/tools.cpp | 3 +++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 apps/opencs/model/tools/spellcheck.cpp create mode 100644 apps/opencs/model/tools/spellcheck.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 87221d7af5..76d4280c8f 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -36,7 +36,7 @@ opencs_units (model/tools opencs_units_noqt (model/tools stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck - birthsigncheck + birthsigncheck spellcheck ) diff --git a/apps/opencs/model/tools/spellcheck.cpp b/apps/opencs/model/tools/spellcheck.cpp new file mode 100644 index 0000000000..3adee0a4ef --- /dev/null +++ b/apps/opencs/model/tools/spellcheck.cpp @@ -0,0 +1,35 @@ + +#include "spellcheck.hpp" + +#include +#include + +#include + +#include "../world/universalid.hpp" + +CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection& spells) +: mSpells (spells) +{} + +int CSMTools::SpellCheckStage::setup() +{ + return mSpells.getSize(); +} + +void CSMTools::SpellCheckStage::perform (int stage, std::vector& messages) +{ + const ESM::Spell& spell = mSpells.getRecord (stage).get(); + + CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId); + + // test for empty name and description + if (spell.mName.empty()) + messages.push_back (id.toString() + "|" + spell.mId + " has an empty name"); + + // test for invalid cost values + if (spell.mData.mCost<0) + messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs"); + + /// \todo check data members that can't be edited in the table view +} \ No newline at end of file diff --git a/apps/opencs/model/tools/spellcheck.hpp b/apps/opencs/model/tools/spellcheck.hpp new file mode 100644 index 0000000000..0566392193 --- /dev/null +++ b/apps/opencs/model/tools/spellcheck.hpp @@ -0,0 +1,29 @@ +#ifndef CSM_TOOLS_SPELLCHECK_H +#define CSM_TOOLS_SPELLCHECK_H + +#include + +#include "../world/idcollection.hpp" + +#include "stage.hpp" + +namespace CSMTools +{ + /// \brief VerifyStage: make sure that spell records are internally consistent + class SpellCheckStage : public Stage + { + const CSMWorld::IdCollection& mSpells; + + public: + + SpellCheckStage (const CSMWorld::IdCollection& spells); + + virtual int setup(); + ///< \return number of steps + + virtual void perform (int stage, std::vector& messages); + ///< Messages resulting from this tage will be appended to \a messages. + }; +} + +#endif diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 78796de418..803861203c 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -19,6 +19,7 @@ #include "soundcheck.hpp" #include "regioncheck.hpp" #include "birthsigncheck.hpp" +#include "spellcheck.hpp" CSMTools::Operation *CSMTools::Tools::get (int type) { @@ -72,6 +73,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier() mVerifier->appendStage (new RegionCheckStage (mData.getRegions())); mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns())); + + mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); } return mVerifier; From be4a01bdb4edf99ca9618ea477f31f44366fc85e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 14:27:32 +0200 Subject: [PATCH 0370/1537] added missing recrod type columns --- apps/opencs/model/world/data.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 84b49b6bcd..14aff47e89 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -33,11 +33,13 @@ CSMWorld::Data::Data() mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); + mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); mSkills.addColumn (new StringIdColumn); mSkills.addColumn (new RecordStateColumn); + mSkills.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Skill)); mSkills.addColumn (new AttributeColumn); mSkills.addColumn (new SpecialisationColumn); for (int i=0; i<4; ++i) @@ -46,6 +48,7 @@ CSMWorld::Data::Data() mClasses.addColumn (new StringIdColumn); mClasses.addColumn (new RecordStateColumn); + mClasses.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Class)); mClasses.addColumn (new NameColumn); mClasses.addColumn (new AttributesColumn (0)); mClasses.addColumn (new AttributesColumn (1)); @@ -59,6 +62,7 @@ CSMWorld::Data::Data() mFactions.addColumn (new StringIdColumn); mFactions.addColumn (new RecordStateColumn); + mFactions.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Faction)); mFactions.addColumn (new NameColumn); mFactions.addColumn (new AttributesColumn (0)); mFactions.addColumn (new AttributesColumn (1)); @@ -68,6 +72,7 @@ CSMWorld::Data::Data() mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); + mRaces.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Race)); mRaces.addColumn (new NameColumn); mRaces.addColumn (new DescriptionColumn); mRaces.addColumn (new FlagColumn ("Playable", 0x1)); @@ -79,6 +84,7 @@ CSMWorld::Data::Data() mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); + mSounds.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Sound)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_Volume)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MinRange)); mSounds.addColumn (new SoundParamColumn (SoundParamColumn::Type_MaxRange)); @@ -86,21 +92,25 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); + mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); + mRegions.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Region)); mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); + mBirthsigns.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Birthsign)); mBirthsigns.addColumn (new NameColumn); mBirthsigns.addColumn (new TextureColumn); mBirthsigns.addColumn (new DescriptionColumn); mSpells.addColumn (new StringIdColumn); mSpells.addColumn (new RecordStateColumn); + mSpells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Spell)); mSpells.addColumn (new NameColumn); mSpells.addColumn (new SpellTypeColumn); mSpells.addColumn (new CostColumn); From cd33f40c8fb1497b3db6eae569a45a9c334cf9d4 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 9 Apr 2013 14:28:31 +0200 Subject: [PATCH 0371/1537] re-enabled opening of record subviews via double click in table --- apps/opencs/view/world/tablesubview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index f4deceb490..bb4bb76c61 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -21,6 +21,5 @@ void CSVWorld::TableSubView::setEditLock (bool locked) void CSVWorld::TableSubView::rowActivated (const QModelIndex& index) { - /// \todo re-enable, after dialogue sub views have been fixed up -// focusId (mTable->getUniversalId (index.row())); + focusId (mTable->getUniversalId (index.row())); } \ No newline at end of file From 46925e93a6f79402f0838eabab30f02c4352a828 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 16:14:08 +0200 Subject: [PATCH 0372/1537] Second minor fix --- apps/openmw/mwclass/armor.cpp | 3 +++ apps/openmw/mwworld/actionequip.cpp | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index ddab6f7548..a14b2667e1 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -343,6 +343,9 @@ namespace MWClass { MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if(weapon == invStore.end()) + return 1; + if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index d5927b6c55..82431ac8f3 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -18,6 +18,7 @@ namespace MWWorld void ActionEquip::executeImp (const Ptr& actor) { + MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); // slots that this item can be equipped in @@ -27,7 +28,7 @@ namespace MWWorld MWWorld::ContainerStoreIterator it = invStore.begin(); for (; it != invStore.end(); ++it) { - if (*it == getTarget()) + if (*it == object) { break; } @@ -43,7 +44,7 @@ namespace MWWorld for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (getTarget()).canBeEquipped (actor, getTarget())) + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) { case 0: return; @@ -70,10 +71,10 @@ namespace MWWorld } } - std::string script = MWWorld::Class::get(*it).getScript(*it); + std::string script = MWWorld::Class::get(object).getScript(object); /* Set OnPCEquip Variable on item's script, if the player is equipping it, and it has a script with that variable declared */ if(equipped && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && script != "") - (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); + (object).mRefData->getLocals().setVarByInt(script, "onpcequip", 1); } } From 9f9d978b0f1020777403f2b5f2e67b7ed0a03cd7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 09:07:05 -0700 Subject: [PATCH 0373/1537] Use an enum to specify the NPC's view mode (normal, head only) --- apps/openmw/mwrender/characterpreview.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.cpp | 8 ++++---- apps/openmw/mwrender/npcanimation.hpp | 10 ++++++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 616543a7d4..0da20f3daf 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -59,8 +59,8 @@ namespace MWRender mNode = renderRoot->createChildSceneNode(); - mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), + 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); mNode->setVisible (false); @@ -101,8 +101,8 @@ namespace MWRender assert(mAnimation); delete mAnimation; - mAnimation = new NpcAnimation(mCharacter, mNode, - MWWorld::Class::get(mCharacter).getInventoryStore (mCharacter), 0, renderHeadOnly()); + mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), + 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); float scale=1.f; MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d7620a8de5..685edb68c8 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -56,7 +56,7 @@ NpcAnimation::~NpcAnimation() } -NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly) +NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWorld::InventoryStore& inv, int visibilityFlags, ViewMode viewMode) : Animation(ptr), mStateID(-1), mTimeToChange(0), @@ -73,7 +73,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveL(inv.end()), mGloveR(inv.end()), mSkirtIter(inv.end()), - mHeadOnly(headOnly) + mViewMode(viewMode) { mNpc = mPtr.get()->mBase; @@ -222,7 +222,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; - for(size_t i = 0;i < slotlistsize && !mHeadOnly;i++) + for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -259,7 +259,7 @@ void NpcAnimation::updateParts(bool forceupdate) if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); - if (mHeadOnly) + if(mViewMode == VM_HeadOnly) return; static const struct { diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 224d174f43..44639e94ab 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -26,6 +26,11 @@ struct PartInfo { const char name[32]; }; +enum ViewMode { + VM_Normal, + VM_HeadOnly +}; + private: static const size_t sPartListSize = 27; static const PartInfo sPartList[sPartListSize]; @@ -39,7 +44,7 @@ private: std::string mHeadModel; std::string mHairModel; std::string mBodyPrefix; - bool mHeadOnly; + ViewMode mViewMode; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -73,7 +78,8 @@ private: public: NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, - MWWorld::InventoryStore& inv, int visibilityFlags, bool headOnly=false); + MWWorld::InventoryStore& inv, int visibilityFlags, + ViewMode viewMode=VM_Normal); virtual ~NpcAnimation(); virtual Ogre::Vector3 runAnimation(float timepassed); From 029d56572777fcccf01639166af528b63c2837e3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 09:23:07 -0700 Subject: [PATCH 0374/1537] Avoid calling setVisible for character previews --- apps/openmw/mwrender/characterpreview.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 0da20f3daf..8396acaea8 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -62,8 +62,6 @@ namespace MWRender mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); - mNode->setVisible (false); - Ogre::Vector3 scale = mNode->getScale(); mCamera->setPosition(mPosition * scale); mCamera->lookAt(mLookAt * scale); @@ -108,8 +106,6 @@ namespace MWRender MWWorld::Class::get(mCharacter).adjustScale(mCharacter, scale); mNode->setScale(Ogre::Vector3(scale)); - mNode->setVisible (false); - mCamera->setPosition(mPosition * mNode->getScale()); mCamera->lookAt(mLookAt * mNode->getScale()); @@ -139,12 +135,8 @@ namespace MWRender mNode->setOrientation (Ogre::Quaternion::IDENTITY); - mNode->setVisible (true); - mRenderTarget->update(); mSelectionBuffer->update(); - - mNode->setVisible (false); } int InventoryPreview::getSlotSelected (int posX, int posY) @@ -178,9 +170,7 @@ namespace MWRender updateCamera(); - mNode->setVisible (true); mRenderTarget->update(); - mNode->setVisible (false); } void RaceSelectionPreview::setPrototype(const ESM::NPC &proto) From 44ef02eb99c2cf7f4cab6d60320e155fe5183579 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:04:59 +0200 Subject: [PATCH 0375/1537] Third minor fix --- apps/openmw/mwworld/actionequip.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 82431ac8f3..2877a2c5ae 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -40,19 +40,20 @@ namespace MWWorld bool equipped = false; + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + { + case 0: + return; //Item cannot be equipped, so function breaks. + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + } + // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) { - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) - { - case 0: - return; - case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - } // if all slots are occupied, replace the last slot if (slot == --slots.first.end()) From 248fff6eb7323b7c7cf4f56afff53c1b820e6fb3 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:41:03 +0200 Subject: [PATCH 0376/1537] Fourth minor fix --- apps/openmw/mwworld/actionequip.cpp | 4 +++- apps/openmw/mwworld/inventorystore.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 2877a2c5ae..39c5abe345 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -43,11 +43,13 @@ namespace MWWorld switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) { case 0: - return; //Item cannot be equipped, so function breaks. + return; case 2: invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; case 3: invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; } // equip the item in the first free slot diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 9f51db3534..782e3f920f 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -192,8 +192,10 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) continue; case 2: invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; case 3: invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; } if (!itemsSlots.second) // if itemsSlots.second is true, item can stay stacked when equipped From bd93e63150dc69c0e3caf27231dfbede99772baf Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 9 Apr 2013 19:46:27 +0200 Subject: [PATCH 0377/1537] Fifth minor fix --- apps/openmw/mwworld/actionequip.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index 39c5abe345..fd35d0dd3c 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,6 +21,18 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); + switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + { + case 0: + return; + case 2: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); + break; + case 3: + invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); + break; + } + // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(getTarget()).getEquipmentSlots(getTarget()); @@ -40,18 +52,6 @@ namespace MWWorld bool equipped = false; - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) - { - case 0: - return; - case 2: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedLeft, invStore.end()); - break; - case 3: - invStore.equip(MWWorld::InventoryStore::Slot_CarriedRight, invStore.end()); - break; - } - // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); slot!=slots.first.end(); ++slot) From 6ca2b1af743b659e44b9601f99c985a92a66e99a Mon Sep 17 00:00:00 2001 From: Tom Mason Date: Tue, 9 Apr 2013 19:24:41 +0100 Subject: [PATCH 0378/1537] fix for turning animations playing when in vanity mode --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwinput/inputmanagerimp.cpp | 13 +++++++++++-- apps/openmw/mwrender/renderingmanager.cpp | 10 ++++++++++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 5 +++++ apps/openmw/mwworld/worldimp.hpp | 2 ++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 040dc703c0..39e985890a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -319,6 +319,7 @@ namespace MWBase virtual void allowVanityMode(bool allow) = 0; virtual void togglePlayerLooking(bool enable) = 0; virtual void changeVanityModeScale(float factor) = 0; + virtual bool vanityRotateCamera(float * rot) = 0; virtual void renderPlayer() = 0; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index c23106be1a..6a34161e08 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -533,8 +533,17 @@ namespace MWInput float scale = MWBase::Environment::get().getFrameDuration(); if(scale <= 0.0f) scale = 1.0f; - mPlayer.setYaw(x/scale); - mPlayer.setPitch(-y/scale); + float rot[3]; + rot[0] = -y; + rot[1] = 0.0f; + rot[2] = x; + + // Only actually turn player when we're not in vanity mode + if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot)) + { + mPlayer.setYaw(x/scale); + mPlayer.setPitch(-y/scale); + } if (arg.state.Z.rel) MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index cd5ab19b9d..029cf394b4 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -891,6 +891,16 @@ void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float mPlayer->getSightAngles(pitch, yaw); } +bool RenderingManager::vanityRotateCamera(float* rot) +{ + if(!mPlayer->isVanityOrPreviewModeEnabled()) + return false; + + Ogre::Vector3 vRot(rot); + mPlayer->rotateCamera(vRot, true); + return true; +} + void RenderingManager::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y) { return mLocalMap->getInteriorMapPosition (position, nX, nY, x, y); diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index b343a60bdb..cece7a95f0 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -88,6 +88,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList mPlayer->setCameraDistance(-factor/120.f*10, true, true); } + bool vanityRotateCamera(float* rot); + void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw); void attachCameraTo(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ae9b7a06b7..11ccd8f2fc 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1364,6 +1364,11 @@ namespace MWWorld return physactor && physactor->getOnGround(); } + bool World::vanityRotateCamera(float * rot) + { + return mRendering->vanityRotateCamera(rot); + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5ae87a1ff7..7b12babee9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -361,6 +361,8 @@ namespace MWWorld mRendering->changeVanityModeScale(factor); } + virtual bool vanityRotateCamera(float * rot); + virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 0e7d555cdf5ebd475792ffe13c0ad7d653288267 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 9 Apr 2013 20:31:00 +0200 Subject: [PATCH 0379/1537] Terrain material now uses multiple passes if required, which means it can support an arbitrary number of layers. Also re-enables PSSM. --- apps/openmw/mwgui/settingswindow.cpp | 4 +- apps/openmw/mwrender/shadows.cpp | 5 +- apps/openmw/mwrender/terrainmaterial.cpp | 161 ++++++++++++++++------- apps/openmw/mwrender/terrainmaterial.hpp | 3 + files/materials/shadowcaster.shader | 3 +- files/materials/terrain.shader | 33 ++++- 6 files changed, 148 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 58754472dd..5fb6e5000b 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -236,9 +236,7 @@ namespace MWGui mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}"); mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows")); - //mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); - mShadowsLargeDistance->setCaptionWithReplacing("#{sOff}"); - mShadowsLargeDistance->setEnabled (false); + mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}"); mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}"); mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}"); diff --git a/apps/openmw/mwrender/shadows.cpp b/apps/openmw/mwrender/shadows.cpp index 595a82294b..0d066a0ecb 100644 --- a/apps/openmw/mwrender/shadows.cpp +++ b/apps/openmw/mwrender/shadows.cpp @@ -28,10 +28,7 @@ void Shadows::recreate() { bool enabled = Settings::Manager::getBool("enabled", "Shadows"); - // Split shadow maps are currently disabled because the terrain cannot cope with them - // (Too many texture units) Solution would be a multi-pass terrain material - //bool split = Settings::Manager::getBool("split", "Shadows"); - const bool split = false; + bool split = Settings::Manager::getBool("split", "Shadows"); sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false"); sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false"); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 8a568883df..dd74254be6 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -68,59 +68,113 @@ namespace MWRender Ogre::MaterialManager::getSingleton().remove(matName); mMaterial = sh::Factory::getInstance().createMaterialInstance (matName); - mMaterial->setProperty ("allow_fixed_function", sh::makeProperty(new sh::BooleanValue(false))); - sh::MaterialInstancePass* p = mMaterial->createPass (); + int numPasses = getRequiredPasses(terrain); + int maxLayersInOnePass = getMaxLayersPerPass(terrain); - p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); - p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); - - p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); - - // global colour map - sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); - colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); - colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - - // global normal map - sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); - normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); - normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - - Ogre::uint maxLayers = getMaxLayers(terrain); - Ogre::uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount()); - Ogre::uint numLayers = std::min(maxLayers, static_cast(terrain->getLayerCount())); - - p->mShaderProperties.setProperty ("num_layers", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numLayers)))); - p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); - - // blend maps - for (Ogre::uint i = 0; i < numBlendTextures; ++i) + for (int pass=0; passcreateTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); - blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(i)))); - blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); - } + int layerOffset = maxLayersInOnePass * pass; + int blendmapOffset = (pass == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map - // layer maps - for (Ogre::uint i = 0; i < numLayers; ++i) - { - sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); - diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(i, 0)))); - p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), - sh::makeProperty(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4)) + "." + getComponent(int((i-1) % 4))))); - } + sh::MaterialInstancePass* p = mMaterial->createPass (); - // shadow - for (Ogre::uint i = 0; i < 3; ++i) - { - sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); - shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); - } + p->setProperty ("vertex_program", sh::makeProperty(new sh::StringValue("terrain_vertex"))); + p->setProperty ("fragment_program", sh::makeProperty(new sh::StringValue("terrain_fragment"))); + if (pass != 0) + { + p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend"))); + // Only write if depth is equal to the depth value written by the previous pass. + p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal"))); + } - p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty(new sh::StringValue( - Ogre::StringConverter::toString(numBlendTextures + numLayers + 2)))); + p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap))); + p->mShaderProperties.setProperty ("is_first_pass", sh::makeProperty(new sh::BooleanValue(pass == 0))); + + // global colour map + sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap"); + colourMap->setProperty ("texture_alias", sh::makeProperty (new sh::StringValue(mMaterial->getName() + "_colourMap"))); + colourMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + // global normal map + sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap"); + normalMap->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getTerrainNormalMap ()->getName()))); + normalMap->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + + Ogre::uint numLayersInThisPass = std::min(maxLayersInOnePass, terrain->getLayerCount()-layerOffset); + + // HACK: Terrain::getLayerBlendTextureIndex should be const, but it is not. + // Remove this once ogre got fixed. + Ogre::Terrain* nonconstTerrain = const_cast(terrain); + + // a blend map might be shared between two passes + // so we can't just use terrain->getBlendTextureCount() + Ogre::uint numBlendTextures=0; + std::vector blendTextures; + for (unsigned int layer=blendmapOffset; layergetBlendTextureName(nonconstTerrain->getLayerBlendTextureIndex( + static_cast(layerOffset+layer)).first); + if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end()) + { + blendTextures.push_back(blendTextureName); + ++numBlendTextures; + } + } + + p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass)))); + p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures)))); + + // blend maps + // the index of the first blend map used in this pass + int blendmapStart; + if (terrain->getLayerCount() == 1) // special case. if there's only one layer, we don't need blend maps at all + blendmapStart = 0; + else + blendmapStart = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+blendmapOffset)).first; + for (Ogre::uint i = 0; i < numBlendTextures; ++i) + { + sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i)); + blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(blendmapStart+i)))); + blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp"))); + } + + // layer maps + for (Ogre::uint i = 0; i < numLayersInThisPass; ++i) + { + sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i)); + diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(layerOffset+i, 0)))); + + if (i+layerOffset > 0) + { + int blendTextureIndex = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+i)).first; + int blendTextureComponent = nonconstTerrain->getLayerBlendTextureIndex(static_cast(layerOffset+i)).second; + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + getComponent(blendTextureComponent)))); + } + else + { + // just to make it shut up about blendmap_component_0 not existing in the first pass. + // it might be retrieved, but will never survive the preprocessing step. + p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i), + sh::makeProperty (new sh::StringValue(""))); + } + } + + // shadow + for (Ogre::uint i = 0; i < 3; ++i) + { + sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i)); + shadowTex->setProperty ("content_type", sh::makeProperty (new sh::StringValue("shadow"))); + } + + p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue( + Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass + 2)))); + + // make sure the pass index is fed to the permutation handler, because blendmap components may be different + p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(pass))); + } return Ogre::MaterialManager::getSingleton().getByName(matName); } @@ -142,6 +196,11 @@ namespace MWRender } Ogre::uint8 TerrainMaterial::Profile::getMaxLayers(const Ogre::Terrain* terrain) const + { + return 255; + } + + int TerrainMaterial::Profile::getMaxLayersPerPass (const Ogre::Terrain* terrain) { // count the texture units free Ogre::uint8 freeTextureUnits = 16; @@ -151,11 +210,21 @@ namespace MWRender --freeTextureUnits; // shadow --freeTextureUnits; + --freeTextureUnits; + --freeTextureUnits; // each layer needs 1.25 units (1xdiffusespec, 0.25xblend) return static_cast(freeTextureUnits / (1.25f)); } + int TerrainMaterial::Profile::getRequiredPasses (const Ogre::Terrain* terrain) + { + int maxLayersPerPass = getMaxLayersPerPass(terrain); + assert(terrain->getLayerCount()); + assert(maxLayersPerPass); + return std::ceil(static_cast(terrain->getLayerCount()) / maxLayersPerPass); + } + void TerrainMaterial::Profile::updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain) { } diff --git a/apps/openmw/mwrender/terrainmaterial.hpp b/apps/openmw/mwrender/terrainmaterial.hpp index fe1214cf5e..c90499baeb 100644 --- a/apps/openmw/mwrender/terrainmaterial.hpp +++ b/apps/openmw/mwrender/terrainmaterial.hpp @@ -72,6 +72,9 @@ namespace MWRender private: sh::MaterialInstance* mMaterial; + int getRequiredPasses (const Ogre::Terrain* terrain); + int getMaxLayersPerPass (const Ogre::Terrain* terrain); + bool mGlobalColourMap; }; diff --git a/files/materials/shadowcaster.shader b/files/materials/shadowcaster.shader index b312d414c5..b992366a7e 100644 --- a/files/materials/shadowcaster.shader +++ b/files/materials/shadowcaster.shader @@ -45,8 +45,7 @@ // use alpha channel of the first texture float alpha = shSample(texture1, UV).a; - // discard if alpha is less than 0.5 - if (alpha < 1.0) + if (alpha < 0.5) discard; #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index c73b582f8d..de90a6cf61 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -1,6 +1,6 @@ #include "core.h" -#define IS_FIRST_PASS 1 +#define IS_FIRST_PASS (@shPropertyString(pass_index) == 0) #define FOG @shGlobalSettingBool(fog) @@ -23,6 +23,9 @@ #define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix) +#if !IS_FIRST_PASS +// This is not the first pass. +#endif #if NEED_DEPTH @shAllocatePassthrough(1, depth) @@ -222,7 +225,11 @@ float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel); #endif - + +#if !IS_FIRST_PASS +float combinedAlpha = 0.f; +#endif + // Layer calculations @shForeach(@shPropertyString(num_blendmaps)) float4 blendValues@shIterator = shSample(blendMap@shIterator, UV); @@ -232,12 +239,20 @@ @shForeach(@shPropertyString(num_layers)) -#if IS_FIRST_PASS == 1 && @shIterator == 0 - // first layer of first pass doesn't need a blend map +#if IS_FIRST_PASS + #if @shIterator == 0 + // first layer of first pass is the base layer and doesn't need a blend map albedo = shSample(diffuseMap0, UV * 10).rgb; -#else + #else albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); - + #endif +#else + #if @shIterator == 0 + albedo = shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator); + #else + albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); + #endif + combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator); #endif @shEndForeach @@ -325,6 +340,12 @@ // prevent negative colour output (for example with negative lights) shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0)); + +#if IS_FIRST_PASS + shOutputColour(0).a = 1; +#else + shOutputColour(0).a = min(combinedAlpha, 1.f); +#endif } #endif From a700c50e84e06586e3a766940e43f33e156d67ee Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 15:10:14 -0700 Subject: [PATCH 0380/1537] Add a first-person view mode to NpcAnimation And use it instead of showing/hiding the player. --- apps/openmw/mwrender/animation.cpp | 2 +- apps/openmw/mwrender/npcanimation.cpp | 64 ++++++++++++++++++++++----- apps/openmw/mwrender/npcanimation.hpp | 3 ++ apps/openmw/mwrender/player.cpp | 12 +++-- 4 files changed, 65 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 067e856720..a849b20efe 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -476,7 +476,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::Vector3 Animation::runAnimation(float timepassed) { - Ogre::Vector3 movement = Ogre::Vector3::ZERO; + Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; while(mCurrentAnim && mPlaying) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 685edb68c8..7e59f8f6c9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -130,7 +130,40 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); setAnimationSources(skelnames); - updateParts(true); + forceUpdate(); +} + +void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) +{ + assert(viewMode != VM_HeadOnly); + mViewMode = viewMode; + + /* FIXME: Enable this once first-person animations work. */ +#if 0 + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mNpc->mRace); + + bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; + std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); + + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + if(mViewMode == VM_FirstPerson) + { + smodel = (!isBeast ? "meshes\\base_anim.1st.nif" : "meshes\\base_animkna.1st.nif"); + skelnames.push_back(smodel); + } + setAnimationSources(skelnames); +#endif + + for(size_t i = 0;i < sPartListSize;i++) + removeIndividualPart(i); + forceUpdate(); } void NpcAnimation::updateParts(bool forceupdate) @@ -254,13 +287,18 @@ void NpcAnimation::updateParts(bool forceupdate) reserveIndividualPart(slotlist[i].reserveParts[res], slotlist[i].slot, prio); } - if(mPartPriorities[ESM::PRT_Head] < 1) - addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); - if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) - addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); - + if(mViewMode != VM_FirstPerson) + { + if(mPartPriorities[ESM::PRT_Head] < 1) + addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); + if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) + addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); + } if(mViewMode == VM_HeadOnly) return; + /* FIXME: Remove this once we figure out how to show what in first-person */ + if(mViewMode == VM_FirstPerson) + return; static const struct { ESM::PartReferenceType type; @@ -288,6 +326,7 @@ void NpcAnimation::updateParts(bool forceupdate) { ESM::PRT_Tail, { "tail", "" } } }; + const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) { @@ -298,14 +337,14 @@ void NpcAnimation::updateParts(bool forceupdate) if(!mNpc->isMale()) { - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]); + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext); if(part == 0) - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]); + part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext); } if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]); + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext); if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]); + part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext); if(part) addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); @@ -431,6 +470,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(int type, int group, int priority, void NpcAnimation::addPartGroup(int group, int priority, const std::vector &parts) { + const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; for(std::size_t i = 0; i < parts.size(); i++) { const ESM::PartReference &part = parts[i]; @@ -440,9 +480,9 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorisMale()) - bodypart = partStore.search(part.mFemale); + bodypart = partStore.search(part.mFemale+ext); if(!bodypart) - bodypart = partStore.search(part.mMale); + bodypart = partStore.search(part.mMale+ext); if(bodypart) addOrReplaceIndividualPart(part.mPart, group, priority, "meshes\\"+bodypart->mModel); diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index 44639e94ab..f2f4c66697 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -28,6 +28,7 @@ struct PartInfo { enum ViewMode { VM_Normal, + VM_FirstPerson, VM_HeadOnly }; @@ -84,6 +85,8 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); + void setViewMode(ViewMode viewMode); + void forceUpdate() { updateParts(true); } }; diff --git a/apps/openmw/mwrender/player.cpp b/apps/openmw/mwrender/player.cpp index 55fda326fa..439264f3af 100644 --- a/apps/openmw/mwrender/player.cpp +++ b/apps/openmw/mwrender/player.cpp @@ -124,8 +124,6 @@ namespace MWRender MWBase::Environment::get().getWindowManager ()->showCrosshair (!MWBase::Environment::get().getWindowManager ()->isGuiMode () && (mFirstPersonView && !mVanity.enabled && !mPreviewMode)); - /// \fixme We shouldn't hide the whole model, just certain components of the character (head, chest, feet, etc) - mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); if (mFirstPersonView && !mVanity.enabled) { return; } @@ -139,6 +137,8 @@ namespace MWRender void Player::toggleViewMode() { mFirstPersonView = !mFirstPersonView; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); if (mFirstPersonView) { mCamera->setPosition(0.f, 0.f, 0.f); setLowHeight(false); @@ -168,6 +168,9 @@ namespace MWRender mVanity.enabled = enable; mVanity.forced = force && enable; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); + float offset = mPreviewCam.offset; Ogre::Vector3 rot(0.f, 0.f, 0.f); if (mVanity.enabled) { @@ -194,6 +197,8 @@ namespace MWRender return; } mPreviewMode = enable; + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); float offset = mCamera->getPosition().z; if (mPreviewMode) { mMainCam.offset = offset; @@ -305,7 +310,8 @@ namespace MWRender delete mAnimation; mAnimation = anim; - mPlayerNode->setVisible(mVanity.enabled || mPreviewMode || !mFirstPersonView); + mAnimation->setViewMode((mVanity.enabled || mPreviewMode || !mFirstPersonView) ? + NpcAnimation::VM_Normal : NpcAnimation::VM_FirstPerson); } void Player::setHeight(float height) From 50d8353a8db9bdeb5f577449e7ae784a3f15bd70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Apr 2013 16:51:04 -0700 Subject: [PATCH 0381/1537] Fix a hack so arms dont show in first-person --- apps/openmw/mwrender/npcanimation.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7e59f8f6c9..96220f47d0 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -255,6 +255,14 @@ void NpcAnimation::updateParts(bool forceupdate) if(!forceupdate) return; + /* FIXME: Remove this once we figure out how to show what in first-person */ + if(mViewMode == VM_FirstPerson) + { + for(size_t i = 0;i < slotlistsize;i++) + this->*slotlist[i].part = inv.getSlot(slotlist[i].slot); + return; + } + for(size_t i = 0;i < slotlistsize && mViewMode != VM_HeadOnly;i++) { MWWorld::ContainerStoreIterator iter = inv.getSlot(slotlist[i].slot); @@ -296,9 +304,6 @@ void NpcAnimation::updateParts(bool forceupdate) } if(mViewMode == VM_HeadOnly) return; - /* FIXME: Remove this once we figure out how to show what in first-person */ - if(mViewMode == VM_FirstPerson) - return; static const struct { ESM::PartReferenceType type; From ce9bc6d9bae9d03b8c614e781b420789eb9531d4 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 00:32:05 -0400 Subject: [PATCH 0382/1537] MwGui windowManager calls fixed to use MWBase::Environment::get().getWindowManager, filenames in MwGui now comply with naming conventions --- apps/openmw/mwgui/alchemywindow.cpp | 17 +- apps/openmw/mwgui/alchemywindow.hpp | 4 +- apps/openmw/mwgui/birth.cpp | 9 +- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 2 +- apps/openmw/mwgui/class.cpp | 93 ++-- apps/openmw/mwgui/class.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 2 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 46 +- apps/openmw/mwgui/dialogue.hpp | 2 +- apps/openmw/mwgui/dialoguehistory.cpp | 76 +++ apps/openmw/mwgui/dialoguehistory.hpp | 19 + apps/openmw/mwgui/enchantingdialog.cpp | 42 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/hud.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 20 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/levelupdialog.cpp | 2 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 8 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 446 +++++++++++++++++ apps/openmw/mwgui/mapwindow.hpp | 107 ++++ apps/openmw/mwgui/merchantrepair.cpp | 10 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 5 +- apps/openmw/mwgui/messagebox.hpp | 8 +- apps/openmw/mwgui/quickkeysmenu.cpp | 20 +- apps/openmw/mwgui/quickkeysmenu.hpp | 2 +- apps/openmw/mwgui/race.cpp | 26 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 2 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 11 +- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 14 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 14 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 21 +- apps/openmw/mwgui/spellcreationdialog.hpp | 2 +- apps/openmw/mwgui/spellwindow.cpp | 18 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 580 ++++++++++++++++++++++ apps/openmw/mwgui/statswindow.hpp | 83 ++++ apps/openmw/mwgui/textinput.cpp | 70 +++ apps/openmw/mwgui/textinput.hpp | 33 ++ apps/openmw/mwgui/tooltips.cpp | 29 +- apps/openmw/mwgui/tooltips.hpp | 6 +- apps/openmw/mwgui/tradewindow.cpp | 24 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 18 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 18 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 14 +- apps/openmw/mwgui/waitdialog.hpp | 2 +- apps/openmw/mwgui/widgets.cpp | 39 +- apps/openmw/mwgui/widgets.hpp | 8 - apps/openmw/mwgui/windowbase.cpp | 54 ++ apps/openmw/mwgui/windowbase.hpp | 47 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 8 +- apps/openmw/mwgui/windowpinnablebase.cpp | 28 ++ apps/openmw/mwgui/windowpinnablebase.hpp | 28 ++ 72 files changed, 1863 insertions(+), 328 deletions(-) create mode 100644 apps/openmw/mwgui/dialoguehistory.cpp create mode 100644 apps/openmw/mwgui/dialoguehistory.hpp create mode 100644 apps/openmw/mwgui/mapwindow.cpp create mode 100644 apps/openmw/mwgui/mapwindow.hpp create mode 100644 apps/openmw/mwgui/statswindow.cpp create mode 100644 apps/openmw/mwgui/statswindow.hpp create mode 100644 apps/openmw/mwgui/textinput.cpp create mode 100644 apps/openmw/mwgui/textinput.hpp create mode 100644 apps/openmw/mwgui/windowbase.cpp create mode 100644 apps/openmw/mwgui/windowbase.hpp create mode 100644 apps/openmw/mwgui/windowpinnablebase.cpp create mode 100644 apps/openmw/mwgui/windowpinnablebase.hpp diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index ca7f1b913a..1ae534797d 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -64,8 +64,8 @@ namespace MWGui { mAlchemy.clear(); - mWindowManager.removeGuiMode(GM_Alchemy); - mWindowManager.removeGuiMode(GM_Inventory); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Alchemy); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Inventory); } void AlchemyWindow::onCreateButtonClicked(MyGUI::Widget* _sender) @@ -77,40 +77,40 @@ namespace MWGui if (result == MWMechanics::Alchemy::Result_NoName) { - mWindowManager.messageBox("#{sNotifyMessage37}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage37}"); return; } // check if mortar & pestle is available (always needed) if (result == MWMechanics::Alchemy::Result_NoMortarAndPestle) { - mWindowManager.messageBox("#{sNotifyMessage45}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage45}"); return; } // make sure 2 or more ingredients were selected if (result == MWMechanics::Alchemy::Result_LessThanTwoIngredients) { - mWindowManager.messageBox("#{sNotifyMessage6a}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage6a}"); return; } if (result == MWMechanics::Alchemy::Result_NoEffects) { - mWindowManager.messageBox("#{sNotifyMessage8}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); return; } if (result == MWMechanics::Alchemy::Result_Success) { - mWindowManager.messageBox("#{sPotionSuccess}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sPotionSuccess}"); MWBase::Environment::get().getSoundManager()->playSound("potion success", 1.f, 1.f); } else if (result == MWMechanics::Alchemy::Result_RandomFailure) { // potion failed - mWindowManager.messageBox("#{sNotifyMessage8}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage8}"); MWBase::Environment::get().getSoundManager()->playSound("potion fail", 1.f, 1.f); } @@ -232,7 +232,6 @@ namespace MWGui MyGUI::IntCoord coord(0, 0, mEffectsBox->getWidth(), 24); Widgets::MWEffectListPtr effectsWidget = mEffectsBox->createWidget ("MW_StatName", coord, MyGUI::Align::Left | MyGUI::Align::Top); - effectsWidget->setWindowManager(&mWindowManager); Widgets::SpellEffectList _list = Widgets::MWEffectList::effectListFromESM(&list); effectsWidget->setEffectList(_list); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 5f84e73e9b..933975f0c8 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,7 +5,7 @@ #include "../mwmechanics/alchemy.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "container.hpp" #include "widgets.hpp" @@ -38,7 +38,7 @@ namespace MWGui virtual void onReferenceUnavailable() { ; } void update(); - + private: MWMechanics::Alchemy mAlchemy; diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 4b07dd698c..d899ab00b1 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -46,7 +46,7 @@ BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); updateBirths(); @@ -59,9 +59,9 @@ void BirthDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void BirthDialog::open() @@ -221,7 +221,7 @@ void BirthDialog::updateSpells() if (!categories[category].spells.empty()) { MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); - label->setCaption(mWindowManager.getGameSettingString(categories[category].label, "")); + label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); mSpellItems.push_back(label); coord.top += lineHeight; @@ -230,7 +230,6 @@ void BirthDialog::updateSpells() { const std::string &spellId = *it; spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); - spellWidget->setWindowManager(&mWindowManager); spellWidget->setSpellId(spellId); mSpellItems.push_back(spellWidget); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index d3f82dace4..033501f22f 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_BIRTH_H #define MWGUI_BIRTH_H -#include "window_base.hpp" +#include "windowbase.hpp" /* This file contains the dialog for choosing a birth sign. diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 777751069b..d57953d07d 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -102,7 +102,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); - mWindowManager.removeGuiMode(GM_Book); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) @@ -112,7 +112,7 @@ void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) MWWorld::ActionTake take(mBook); take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - mWindowManager.removeGuiMode(GM_Book); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); } void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index a509f131fe..c2a9dca893 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_BOOKWINDOW_H #define MWGUI_BOOKWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index bcf3c335d3..27de7cee98 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -1,6 +1,6 @@ #include "charactercreation.hpp" -#include "text_input.hpp" +#include "textinput.hpp" #include "race.hpp" #include "class.hpp" #include "birth.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index a2f09096a1..8c352d5080 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -26,7 +26,7 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW // Centre dialog center(); - setText("ReflectT", mWindowManager.getGameSettingString("sMessageQuestionAnswer1", "")); + setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); getWidget(mClassImage, "ClassImage"); getWidget(mClassName, "ClassName"); @@ -37,7 +37,7 @@ GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parW MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); } @@ -77,16 +77,12 @@ PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); - mFavoriteAttribute[0]->setWindowManager(&mWindowManager); - mFavoriteAttribute[1]->setWindowManager(&mWindowManager); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - mMajorSkill[i]->setWindowManager(&mWindowManager); - mMinorSkill[i]->setWindowManager(&mWindowManager); } getWidget(mClassList, "ClassList"); @@ -115,9 +111,9 @@ void PickClassDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void PickClassDialog::open() @@ -224,7 +220,7 @@ void PickClassDialog::updateStats() "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[specialization], specIds[specialization]); + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); @@ -365,10 +361,10 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) { setText(""); ButtonList buttons; - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu1", "")); - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu2", "")); - buttons.push_back(mWindowManager.getGameSettingString("sClassChoiceMenu3", "")); - buttons.push_back(mWindowManager.getGameSettingString("sBack", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); setButtons(buttons); } @@ -384,20 +380,18 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("SpecializationT", mWindowManager.getGameSettingString("sChooseClassMenu1", "Specialization")); + setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); getWidget(mSpecializationName, "SpecializationName"); mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); - setText("FavoriteAttributesT", mWindowManager.getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); - mFavoriteAttribute0->setWindowManager(&mWindowManager); - mFavoriteAttribute1->setWindowManager(&mWindowManager); mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - setText("MajorSkillT", mWindowManager.getGameSettingString("sSkillClassMajor", "")); - setText("MinorSkillT", mWindowManager.getGameSettingString("sSkillClassMinor", "")); + setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); + setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); for(int i = 0; i < 5; i++) { char theIndex = '0'+i; @@ -410,11 +404,10 @@ CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) std::vector::const_iterator end = mSkills.end(); for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) { - (*it)->setWindowManager(&mWindowManager); (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); } - setText("LabelT", mWindowManager.getGameSettingString("sName", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); getWidget(mEditName, "EditName"); // Make sure the edit box has focus @@ -522,32 +515,32 @@ void CreateClassDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } // widget controls void CreateClassDialog::onDialogCancel() { - mWindowManager.removeDialog(mSpecDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); mSpecDialog = 0; - mWindowManager.removeDialog(mAttribDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); mAttribDialog = 0; - mWindowManager.removeDialog(mSkillDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); mSkillDialog = 0; - mWindowManager.removeDialog(mDescDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); mDescDialog = 0; } void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(mWindowManager); + mSpecDialog = new SelectSpecializationDialog(*MWBase::Environment::get().getWindowManager()); mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); mSpecDialog->setVisible(true); @@ -558,7 +551,7 @@ void CreateClassDialog::onSpecializationSelected() mSpecializationId = mSpecDialog->getSpecializationId(); setSpecialization(mSpecializationId); - mWindowManager.removeDialog(mSpecDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); mSpecDialog = 0; } @@ -570,7 +563,7 @@ void CreateClassDialog::setSpecialization(int id) "sSpecializationMagic", "sSpecializationStealth" }; - std::string specName = mWindowManager.getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); mSpecializationName->setCaption(specName); ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); } @@ -578,7 +571,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(mWindowManager); + mAttribDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager()); mAffectedAttribute = _sender; mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); @@ -599,7 +592,7 @@ void CreateClassDialog::onAttributeSelected() mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); } mAffectedAttribute->setAttributeId(id); - mWindowManager.removeDialog(mAttribDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); mAttribDialog = 0; update(); @@ -608,7 +601,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(mWindowManager); + mSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager()); mAffectedSkill = _sender; mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); @@ -633,14 +626,14 @@ void CreateClassDialog::onSkillSelected() } mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); - mWindowManager.removeDialog(mSkillDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); mSkillDialog = 0; update(); } void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - mDescDialog = new DescriptionDialog(mWindowManager); + mDescDialog = new DescriptionDialog(*MWBase::Environment::get().getWindowManager()); mDescDialog->setTextInput(mDescription); mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); mDescDialog->setVisible(true); @@ -649,7 +642,7 @@ void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) { mDescription = mDescDialog->getTextInput(); - mWindowManager.removeDialog(mDescDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); mDescDialog = 0; } @@ -673,14 +666,14 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sSpecializationMenu1", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); getWidget(mSpecialization0, "Specialization0"); getWidget(mSpecialization1, "Specialization1"); getWidget(mSpecialization2, "Specialization2"); - std::string combat = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); - std::string magic = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); - std::string stealth = mWindowManager.getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); mSpecialization0->setCaption(combat); mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); @@ -696,7 +689,7 @@ SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& pa MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); } @@ -733,7 +726,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sAttributesMenu1", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); for (int i = 0; i < 8; ++i) { @@ -741,7 +734,6 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan char theIndex = '0'+i; getWidget(attribute, std::string("Attribute").append(1, theIndex)); - attribute->setWindowManager(&parWindowManager); attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); @@ -749,7 +741,7 @@ SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowMan MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); } @@ -780,10 +772,10 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("LabelT", mWindowManager.getGameSettingString("sSkillsMenu1", "")); - setText("CombatLabelT", mWindowManager.getGameSettingString("sSpecializationCombat", "")); - setText("MagicLabelT", mWindowManager.getGameSettingString("sSpecializationMagic", "")); - setText("StealthLabelT", mWindowManager.getGameSettingString("sSpecializationStealth", "")); + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); for(int i = 0; i < 9; i++) { @@ -833,7 +825,6 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) { for (int i = 0; i < 9; ++i) { - mSkills[spec][i].widget->setWindowManager(&mWindowManager); mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); @@ -842,7 +833,7 @@ SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* cancelButton; getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(mWindowManager.getGameSettingString("sCancel", "")); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); } @@ -876,7 +867,7 @@ DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); - okButton->setCaption(mWindowManager.getGameSettingString("sInputMenu1", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); // Make sure the edit box has focus MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 8c60331d87..11da1a7913 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -3,7 +3,7 @@ #include "widgets.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" /* This file contains the dialogs for choosing a class. diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index 45941f2ad0..a925cad550 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_CONFIRMATIONDIALOG_H #define MWGUI_CONFIRMATIONDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 7e6a0b0885..f7846e70ec 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -751,7 +751,7 @@ void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) /// \todo I don't think this is the correct flag to check if (MWWorld::Class::get(mPtr).isEssential(mPtr)) - mWindowManager.messageBox("#{sDisposeCorpseFail}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); else MWBase::Environment::get().getWorld()->deleteObject(mPtr); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 03bd519f7d..7a3e804e5d 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -3,7 +3,7 @@ #include "../mwworld/esmstore.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "../mwclass/container.hpp" diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index 80da6eea01..d5155839d8 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_COUNTDIALOG_H #define MWGUI_COUNTDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index b3aa27617c..0939da1b17 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -18,7 +18,7 @@ #include "../mwdialogue/dialoguemanagerimp.hpp" -#include "dialogue_history.hpp" +#include "dialoguehistory.hpp" #include "widgets.hpp" #include "list.hpp" #include "tradewindow.hpp" @@ -89,17 +89,17 @@ void PersuasionDialog::onPersuade(MyGUI::Widget *sender) else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; else if (sender == mBribe10Button) { - mWindowManager.getTradeWindow()->addOrRemoveGold(-10); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); type = MWBase::MechanicsManager::PT_Bribe10; } else if (sender == mBribe100Button) { - mWindowManager.getTradeWindow()->addOrRemoveGold(-100); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); type = MWBase::MechanicsManager::PT_Bribe100; } else /*if (sender == mBribe1000Button)*/ { - mWindowManager.getTradeWindow()->addOrRemoveGold(-1000); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); type = MWBase::MechanicsManager::PT_Bribe1000; } @@ -113,7 +113,7 @@ void PersuasionDialog::open() WindowModal::open(); center(); - int playerGold = mWindowManager.getInventoryWindow()->getPlayerGold(); + int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); mBribe10Button->setEnabled (playerGold >= 10); mBribe100Button->setEnabled (playerGold >= 100); @@ -251,45 +251,45 @@ void DialogueWindow::onSelectTopic(const std::string& topic, int id) } else if (topic == gmst.find("sCompanionShare")->getString()) { - mWindowManager.pushGuiMode(GM_Companion); - mWindowManager.showCompanionWindow(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); + MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); } else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) { if (topic == gmst.find("sBarter")->getString()) { - mWindowManager.pushGuiMode(GM_Barter); - mWindowManager.getTradeWindow()->startTrade(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); } else if (topic == gmst.find("sSpells")->getString()) { - mWindowManager.pushGuiMode(GM_SpellBuying); - mWindowManager.getSpellBuyingWindow()->startSpellBuying(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); } else if (topic == gmst.find("sTravel")->getString()) { - mWindowManager.pushGuiMode(GM_Travel); - mWindowManager.getTravelWindow()->startTravel(mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); } else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) { - mWindowManager.pushGuiMode(GM_SpellCreation); - mWindowManager.startSpellMaking (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); } else if (topic == gmst.find("sEnchanting")->getString()) { - mWindowManager.pushGuiMode(GM_Enchanting); - mWindowManager.startEnchanting (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); } else if (topic == gmst.find("sServiceTrainingTitle")->getString()) { - mWindowManager.pushGuiMode(GM_Training); - mWindowManager.startTraining (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->startTraining (mPtr); } else if (topic == gmst.find("sRepair")->getString()) { - mWindowManager.pushGuiMode(GM_MerchantRepair); - mWindowManager.startRepair (mPtr); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->startRepair (mPtr); } } } @@ -456,7 +456,7 @@ std::string DialogueWindow::parseText(const std::string& text) } else { - if( !mWindowManager.getTranslationDataStorage().hasTranslation() ) + if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) { @@ -528,7 +528,7 @@ void DialogueWindow::goodbye() void DialogueWindow::onReferenceUnavailable() { - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void DialogueWindow::onFrame() diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index 187731fc77..e78856c951 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_DIALOGE_H #define MWGUI_DIALOGE_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include diff --git a/apps/openmw/mwgui/dialoguehistory.cpp b/apps/openmw/mwgui/dialoguehistory.cpp new file mode 100644 index 0000000000..a122a78916 --- /dev/null +++ b/apps/openmw/mwgui/dialoguehistory.cpp @@ -0,0 +1,76 @@ +#include "dialoguehistory.hpp" + +#include "../mwbase/windowmanager.hpp" + +#include "widgets.hpp" + +#include "../mwworld/esmstore.hpp" + +#include +#include + +#include +#include + +using namespace MWGui; +using namespace Widgets; + +MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) +{ + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::TextIterator iterator(getCaption()); + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if (pos < _pos) + continue; + else if (pos == _pos) + break; + } + return colour; +} + +MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) +{ + bool breakOnNext = false; + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::UString colour2 = colour; + MyGUI::TextIterator iterator(getCaption()); + MyGUI::TextIterator col_start = iterator; + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if(colour != colour2) + { + if(breakOnNext) + { + return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + } + col_start = iterator; + colour2 = colour; + } + if (pos < _pos) + continue; + else if (pos == _pos) + { + breakOnNext = true; + } + } + return ""; +} + +void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) +{ + MyGUI::UString head("\n#D8C09A"); + head.append(parText); + head.append("#B29154\n"); + addText(head); +} + +void DialogueHistory::addDialogText(const MyGUI::UString& parText) +{ + addText(parText); + addText("\n"); +} diff --git a/apps/openmw/mwgui/dialoguehistory.hpp b/apps/openmw/mwgui/dialoguehistory.hpp new file mode 100644 index 0000000000..c37504af77 --- /dev/null +++ b/apps/openmw/mwgui/dialoguehistory.hpp @@ -0,0 +1,19 @@ +#ifndef MWGUI_DIALOGE_HISTORY_H +#define MWGUI_DIALOGE_HISTORY_H +#include + +namespace MWGui +{ + class DialogueHistory : public MyGUI::EditBox + { + MYGUI_RTTI_DERIVED( DialogueHistory ) + public: + Widget* getClient() { return mClient; } + MyGUI::UString getColorAtPos(size_t _pos); + MyGUI::UString getColorTextAt(size_t _pos); + void addDialogHeading(const MyGUI::UString& parText); + void addDialogText(const MyGUI::UString& parText); + }; +} +#endif + diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 276e7a9047..02d847d1a8 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -69,19 +69,19 @@ namespace MWGui switch(mEnchanting.getEnchantType()) { case 0: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastOnce","Cast Once")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastOnce","Cast Once")); mAddEffectDialog.constantEffect=false; break; case 1: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenStrikes", "When Strikes")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenStrikes", "When Strikes")); mAddEffectDialog.constantEffect=false; break; case 2: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastWhenUsed", "When Used")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastWhenUsed", "When Used")); mAddEffectDialog.constantEffect=false; break; case 3: - mTypeButton->setCaption(mWindowManager.getGameSettingString("sItemCastConstant", "Cast Constant")); + mTypeButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sItemCastConstant", "Cast Constant")); mAddEffectDialog.constantEffect=true; break; } @@ -126,20 +126,20 @@ namespace MWGui void EnchantingDialog::onReferenceUnavailable () { - mWindowManager.removeGuiMode (GM_Dialogue); - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } void EnchantingDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } void EnchantingDialog::onSelectItem(MyGUI::Widget *sender) { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", - ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, mWindowManager); + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); @@ -190,7 +190,7 @@ namespace MWGui if(mEnchanting.getGemCharge()==0) { - mWindowManager.messageBox ("#{sNotifyMessage32}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage32}"); return; } @@ -227,14 +227,14 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", - ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, mWindowManager); + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); mItemSelectionDialog->openContainer(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); mItemSelectionDialog->drawItems (); - //mWindowManager.messageBox("#{sInventorySelectNoSoul}"); + //MWBase::Environment::get().getWindowManager()->messageBox("#{sInventorySelectNoSoul}"); } void EnchantingDialog::notifyEffectsChanged () @@ -254,50 +254,50 @@ namespace MWGui { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); return; } if (mName->getCaption ().empty()) { - mWindowManager.messageBox ("#{sNotifyMessage10}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mEnchanting.soulEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage52}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage52}"); return; } if (mEnchanting.itemEmpty()) { - mWindowManager.messageBox ("#{sNotifyMessage11}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage11}"); return; } if (mEnchanting.getEnchantCost() > mEnchanting.getMaxEnchantValue()) { - mWindowManager.messageBox ("#{sNotifyMessage29}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage29}"); return; } mEnchanting.setNewItemName(mName->getCaption()); mEnchanting.setEffect(mEffectList); - if (mEnchanting.getEnchantPrice() > mWindowManager.getInventoryWindow()->getPlayerGold()) + if (mEnchanting.getEnchantPrice() > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } int result = mEnchanting.create(); if(result==1) - mWindowManager.messageBox ("#{sEnchantmentMenu12}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu12}"); else - mWindowManager.messageBox ("#{sNotifyMessage34}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage34}"); - mWindowManager.removeGuiMode (GM_Enchanting); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Enchanting); } } diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index a7861c422d..822199ac67 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_ENCHANTINGDIALOG_H #define MWGUI_ENCHANTINGDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "spellcreationdialog.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index aab9e62a4f..c65566ce3e 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -1,4 +1,4 @@ -#include "map_window.hpp" +#include "mapwindow.hpp" #include diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 001f42bd11..393f03a541 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -130,7 +130,7 @@ namespace MWGui void InventoryWindow::onPinToggled() { - mWindowManager.setWeaponVisibility(!mPinned); + MWBase::Environment::get().getWindowManager()->setWeaponVisibility(!mPinned); } void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender) @@ -162,13 +162,13 @@ 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 - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); mDragAndDrop->mIsOnDragAndDrop = false; MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - mWindowManager.setDragDrop(false); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); drawItems(); @@ -224,11 +224,11 @@ namespace MWGui { invStore.equip(slot, invStore.end()); std::string script = MWWorld::Class::get(*it).getScript(*it); - + // Unset OnPCEquip Variable on item's script, if it has a script with that variable declared if(script != "") (*it).mRefData->getLocals().setVarByInt(script, "onpcequip", 0); - + return; } } @@ -285,16 +285,16 @@ namespace MWGui void InventoryWindow::notifyContentChanged() { // update the spell window just in case new enchanted items were added to inventory - if (mWindowManager.getSpellWindow()) - mWindowManager.getSpellWindow()->updateSpells(); + if (MWBase::Environment::get().getWindowManager()->getSpellWindow()) + MWBase::Environment::get().getWindowManager()->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(); + MWBase::Environment::get().getWindowManager()->unsetSelectedWeapon(); else - mWindowManager.setSelectedWeapon(*weaponSlot); /// \todo track weapon durability + MWBase::Environment::get().getWindowManager()->setSelectedWeapon(*weaponSlot); /// \todo track weapon durability mPreviewDirty = true; diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index fceb7ecef1..61ee17ef93 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -4,7 +4,7 @@ #include "../mwrender/characterpreview.hpp" #include "container.hpp" -#include "window_pinnable_base.hpp" +#include "windowpinnablebase.hpp" #include "widgets.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index cd1ff7ebbd..73a2dca2ec 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -6,7 +6,7 @@ #include #include -#include "window_base.hpp" +#include "windowbase.hpp" #include "imagebutton.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index 67620d49da..dcecdccc1b 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -183,7 +183,7 @@ namespace MWGui creatureStats.setLevel (creatureStats.getLevel()+1); pcStats.levelUp (); - mWindowManager.removeGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Levelup); } } diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index 3c8b74800b..a54948e2a0 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_LEVELUPDIALOG_H #define MWGUI_LEVELUPDIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 86f196d9f5..3066705124 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -195,12 +195,12 @@ namespace MWGui { changeWallpaper(); - mWindowManager.pushGuiMode(GM_LoadingWallpaper); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_LoadingWallpaper); } else { mBackgroundImage->setImageTexture(""); - mWindowManager.pushGuiMode(GM_Loading); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Loading); } } @@ -211,8 +211,8 @@ namespace MWGui mLoadingOn = false; mFirstLoad = false; - mWindowManager.removeGuiMode(GM_Loading); - mWindowManager.removeGuiMode(GM_LoadingWallpaper); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Loading); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_LoadingWallpaper); } void LoadingScreen::changeWallpaper () diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 176fc0f5d5..cb33975ae3 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -4,7 +4,7 @@ #include #include -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp new file mode 100644 index 0000000000..029974d2b3 --- /dev/null +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -0,0 +1,446 @@ +#include "mapwindow.hpp" + +#include + +#include +#include +#include + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" + +#include "../mwrender/globalmap.hpp" + +#include "widgets.hpp" + +using namespace MWGui; + +LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mMapDragAndDrop(false) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) + , mCompass(NULL) +{ +} + +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) +{ + 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 + (-1*(my-1))); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } + notifyMapChanged (); +} + +void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) +{ + applyFogOfWar (); +} + +void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) +{ + applyFogOfWar (); +} + +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 + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + // map + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (-1*(my-1))); + + 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); + else + box->setImageTexture("black.png"); + + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + } + else + { + Ogre::Vector2 position (marker.x, marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + } + + static int counter = 0; + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); + } + + + } + } + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; + + // fog of war + 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; + + notifyPlayerUpdate (); + + 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; + + notifyPlayerUpdate (); + + 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; +} + +// ------------------------------------------------------------------------------------------ + +MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) + , mGlobal(false) +{ + setCoord(500,0,320,300); + + mGlobalMapRender = new MWRender::GlobalMap(cacheDir); + mGlobalMapRender->render(); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + + mGlobalMap->setVisible (false); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing("#{sWorld}"); + + getWidget(mEventBoxGlobal, "EventBoxGlobal"); + mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + getWidget(mEventBoxLocal, "EventBoxLocal"); + mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); +} + +MapWindow::~MapWindow() +{ + delete mGlobalMapRender; +} + +void MapWindow::setCellName(const std::string& cellName) +{ + setTitle("#{sCell=" + cellName + "}"); +} + +void MapWindow::addVisitedLocation(const std::string& name, int x, int y) +{ + float worldX, worldY; + mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); + + MyGUI::IntCoord widgetCoord( + worldX * mGlobalMapRender->getWidth()+6, + worldY * mGlobalMapRender->getHeight()+6, + 12, 12); + + + static int _counter=0; + MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + ++_counter; + + markerWidget = mEventBoxGlobal->createWidget("", + widgetCoord, MyGUI::Align::Default); + markerWidget->setNeedMouseFocus (true); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); +} + +void MapWindow::cellExplored(int x, int y) +{ + mGlobalMapRender->exploreCell(x,y); +} + +void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) +{ + if (_id!=MyGUI::MouseButton::Left) return; + + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); +} + +void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) +{ + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + + if (mGlobal) + globalMapUpdatePlayer (); +} + +void MapWindow::onPinToggled() +{ + MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); +} + +void MapWindow::open() +{ + mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + globalMapUpdatePlayer(); + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); +} + +void MapWindow::globalMapUpdatePlayer () +{ + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + + + // for interiors, we have no choice other than using the last position & direction. + /// \todo save this last position in the savegame? + if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + { + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + + MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(dir.x, dir.y); + rotatingSubskin->setAngle(angle); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + mGlobalMap->setViewOffset(viewoffs); + } +} + +void MapWindow::notifyPlayerUpdate () +{ + globalMapUpdatePlayer (); +} + +void MapWindow::notifyMapChanged () +{ + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); +} diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp new file mode 100644 index 0000000000..329854e182 --- /dev/null +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -0,0 +1,107 @@ +#ifndef MWGUI_MAPWINDOW_H +#define MWGUI_MAPWINDOW_H + +#include "windowpinnablebase.hpp" + +namespace MWRender +{ + class GlobalMap; +} + +namespace MWGui +{ + class LocalMapBase + { + public: + LocalMapBase(); + 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(); + + struct MarkerPosition + { + bool interior; + int cellX; + int cellY; + float nX; + float nY; + }; + + protected: + 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(); + + void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); + + virtual void notifyPlayerUpdate() {} + virtual void notifyMapChanged() {} + + OEngine::GUI::Layout* mLayout; + + bool mMapDragAndDrop; + + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; + }; + + class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase + { + public: + MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); + virtual ~MapWindow(); + + void setCellName(const std::string& cellName); + + void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map + void cellExplored(int x, int y); + + virtual void open(); + + private: + void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); + void onWorldButtonClicked(MyGUI::Widget* _sender); + + void globalMapUpdatePlayer(); + + MyGUI::ScrollView* mGlobalMap; + MyGUI::ImageBox* mGlobalMapImage; + MyGUI::ImageBox* mGlobalMapOverlay; + MyGUI::ImageBox* mPlayerArrowLocal; + MyGUI::ImageBox* mPlayerArrowGlobal; + MyGUI::Button* mButton; + MyGUI::IntPoint mLastDragPos; + bool mGlobal; + + MyGUI::Button* mEventBoxGlobal; + MyGUI::Button* mEventBoxLocal; + + MWRender::GlobalMap* mGlobalMapRender; + + protected: + virtual void onPinToggled(); + + virtual void notifyPlayerUpdate(); + virtual void notifyMapChanged(); + + }; +} +#endif diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 1c9056748b..f24d2d4177 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -72,7 +72,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) MyGUI::Button* button = mList->createWidget( - (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + (price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, currentY, 0, @@ -82,7 +82,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) currentY += 18; - button->setEnabled(price<=mWindowManager.getInventoryWindow()->getPlayerGold()); + button->setEnabled(price<=MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()); button->setUserString("Price", boost::lexical_cast(price)); button->setUserData(*iter); button->setCaptionWithReplacing(name); @@ -95,7 +95,7 @@ void MerchantRepair::startRepair(const MWWorld::Ptr &actor) mList->setCanvasSize (MyGUI::IntSize(mList->getWidth(), std::max(mList->getHeight(), currentY))); mGoldLabel->setCaptionWithReplacing("#{sGold}: " - + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); } void MerchantRepair::onMouseWheel(MyGUI::Widget* _sender, int _rel) @@ -120,14 +120,14 @@ void MerchantRepair::onRepairButtonClick(MyGUI::Widget *sender) MWBase::Environment::get().getSoundManager()->playSound("Repair",1,1); int price = boost::lexical_cast(sender->getUserString("Price")); - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); startRepair(mActor); } void MerchantRepair::onOkButtonClick(MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_MerchantRepair); } } diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 4b7e2b8fbd..2cd6c486a9 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWGUI_MERCHANTREPAIR_H #define OPENMW_MWGUI_MERCHANTREPAIR_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 46663b67a5..58bbc3c3ab 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -7,9 +7,8 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (MWBase::WindowManager *windowManager) +MessageBoxManager::MessageBoxManager (MWBase::WindowManager* windowManager) { - mWindowManager = windowManager; // defines mMessageBoxSpeed = 0.1; mInterMessageBoxe = NULL; @@ -371,7 +370,7 @@ InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxMan void InteractiveMessageBox::enterPressed() { - + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index 859e1806a7..c64953b665 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -3,7 +3,7 @@ #include -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" @@ -40,7 +40,7 @@ namespace MWGui void removeMessageBox (float time, MessageBox *msgbox); bool removeMessageBox (MessageBox *msgbox); void setMessageBoxSpeed (int speed); - + void enterPressed(); int readPressedButton (); @@ -51,8 +51,6 @@ namespace MWGui void onButtonPressed(int button) { eventButtonPressed(button); eventButtonPressed.clear(); } - MWBase::WindowManager *mWindowManager; - private: std::vector mMessageBoxes; InteractiveMessageBox* mInterMessageBoxe; @@ -92,7 +90,7 @@ namespace MWGui private: void buttonActivated (MyGUI::Widget* _widget); - + MessageBoxManager& mMessageBoxManager; MyGUI::EditBox* mMessageWidget; MyGUI::Widget* mButtonsWidget; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2e4bf9100b..82835a8058 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -109,14 +109,14 @@ namespace MWGui { // open assign dialog if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(mWindowManager, this); + mAssignDialog = new QuickKeysMenuAssign(*MWBase::Environment::get().getWindowManager(), this); mAssignDialog->setVisible (true); } } void QuickKeysMenu::onOkButtonClicked (MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_QuickKeysMenu); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_QuickKeysMenu); } @@ -124,7 +124,7 @@ namespace MWGui { if (!mItemSelectionDialog ) { - mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, mWindowManager); + mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, *MWBase::Environment::get().getWindowManager()); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } @@ -139,7 +139,7 @@ namespace MWGui { if (!mMagicSelectionDialog ) { - mMagicSelectionDialog = new MagicSelectionDialog(mWindowManager, this); + mMagicSelectionDialog = new MagicSelectionDialog(*MWBase::Environment::get().getWindowManager(), this); } mMagicSelectionDialog->setVisible(true); @@ -281,7 +281,7 @@ namespace MWGui std::string spellId = button->getChildAt(0)->getUserString("Spell"); spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); - mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } else if (type == Type_Item) { @@ -303,11 +303,11 @@ 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 - mWindowManager.getBookWindow()->setTakeButtonShow(false); - mWindowManager.getScrollWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getBookWindow()->setTakeButtonShow(false); + MWBase::Environment::get().getWindowManager()->getScrollWindow()->setTakeButtonShow(false); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } else if (type == Type_MagicItem) { @@ -341,12 +341,12 @@ namespace MWGui action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item); + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); } } diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 345ffa0c87..d5b6e6cd85 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -4,7 +4,7 @@ #include "../mwworld/ptr.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index be693eb2ba..167ad573a0 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -74,7 +74,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) // Centre dialog center(); - setText("AppearanceT", mWindowManager.getGameSettingString("sRaceMenu1", "Appearance")); + setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); getWidget(mPreviewImage, "PreviewImage"); getWidget(mHeadRotate, "HeadRotate"); @@ -86,34 +86,34 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) // Set up next/previous buttons MyGUI::Button *prevButton, *nextButton; - setText("GenderChoiceT", mWindowManager.getGameSettingString("sRaceMenu2", "Change Sex")); + setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); getWidget(prevButton, "PrevGenderButton"); getWidget(nextButton, "NextGenderButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); - setText("FaceChoiceT", mWindowManager.getGameSettingString("sRaceMenu3", "Change Face")); + setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); getWidget(prevButton, "PrevFaceButton"); getWidget(nextButton, "NextFaceButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - setText("HairChoiceT", mWindowManager.getGameSettingString("sRaceMenu4", "Change Hair")); + setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); getWidget(prevButton, "PrevHairButton"); getWidget(nextButton, "NextHairButton"); prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - setText("RaceT", mWindowManager.getGameSettingString("sRaceMenu5", "Race")); + setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); getWidget(mRaceList, "RaceList"); mRaceList->setScrollVisible(true); mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - setText("SkillsT", mWindowManager.getGameSettingString("sBonusSkillTitle", "Skill Bonus")); + setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); getWidget(mSkillList, "SkillList"); - setText("SpellPowerT", mWindowManager.getGameSettingString("sRaceMenu7", "Specials")); + setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); MyGUI::Button* backButton; @@ -122,7 +122,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) MyGUI::Button* okButton; getWidget(okButton, "OKButton"); - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); updateRaces(); @@ -136,9 +136,9 @@ void RaceDialog::setNextButtonShow(bool shown) getWidget(okButton, "OKButton"); if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); } void RaceDialog::open() @@ -156,7 +156,7 @@ void RaceDialog::open() const ESM::NPC proto = mPreview->getPrototype(); setRaceId(proto.mRace); recountParts(); - + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); mFaceIndex = boost::lexical_cast(index) - 1; @@ -361,7 +361,7 @@ void RaceDialog::updateRaces() const MWWorld::Store &races = MWBase::Environment::get().getWorld()->getStore().get(); - + int index = 0; MWWorld::Store::iterator it = races.begin(); for (; it != races.end(); ++it) @@ -403,7 +403,6 @@ void RaceDialog::updateSkills() skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, std::string("Skill") + boost::lexical_cast(i)); - skillWidget->setWindowManager(&mWindowManager); skillWidget->setSkillNumber(skillId); skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); ToolTips::createSkillToolTip(skillWidget, skillId); @@ -439,7 +438,6 @@ void RaceDialog::updateSpellPowers() { const std::string &spellpower = *it; spellPowerWidget = mSpellPowerList->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); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 0ca440ad53..4a4acd0112 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -8,7 +8,7 @@ #include "../mwrender/characterpreview.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index f53ddc4305..43c262ad85 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -133,7 +133,7 @@ void Repair::updateRepairView() void Repair::onCancel(MyGUI::Widget *sender) { - mWindowManager.removeGuiMode(GM_Repair); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Repair); } void Repair::onRepairItem(MyGUI::Widget *sender) diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index c14b1955bd..824e0b6d2a 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -1,7 +1,7 @@ #ifndef OPENMW_MWGUI_REPAIR_H #define OPENMW_MWGUI_REPAIR_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" #include "../mwmechanics/repair.hpp" diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 50508cc5f0..74b1893456 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -53,15 +53,15 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) // Setup dynamic stats getWidget(mHealth, "Health"); - mHealth->setTitle(mWindowManager.getGameSettingString("sHealth", "")); + mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); mHealth->setValue(45, 45); getWidget(mMagicka, "Magicka"); - mMagicka->setTitle(mWindowManager.getGameSettingString("sMagic", "")); + mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); mMagicka->setValue(50, 50); getWidget(mFatigue, "Fatigue"); - mFatigue->setTitle(mWindowManager.getGameSettingString("sFatigue", "")); + mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); mFatigue->setValue(160, 160); // Setup attributes @@ -71,7 +71,6 @@ ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) { getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); - attribute->setWindowManager(&mWindowManager); attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); } @@ -277,7 +276,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId addSeparator(coord1, coord2); } - addGroup(mWindowManager.getGameSettingString(titleId, titleDefault), coord1, coord2); + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); SkillList::const_iterator end = skills.end(); for (SkillList::const_iterator it = skills.begin(); it != end; ++it) @@ -296,7 +295,7 @@ void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); for (int i=0; i<2; ++i) { diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 4f41ec42d6..9775a52de4 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_REVIEW_H #define MWGUI_REVIEW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwmechanics/stat.hpp" #include "widgets.hpp" diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 3bd3a47439..22884bfe6d 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -66,7 +66,7 @@ void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) @@ -76,5 +76,5 @@ void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) MWWorld::ActionTake take(mScroll); take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - mWindowManager.removeGuiMode(GM_Scroll); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); } diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 42b6395a9a..59b39cab38 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SCROLLWINDOW_H #define MWGUI_SCROLLWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "imagebutton.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 58754472dd..e21d4f5894 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -274,7 +274,7 @@ namespace MWGui void SettingsWindow::onOkButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_Settings); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Settings); } void SettingsWindow::onResolutionSelected(MyGUI::ListBox* _sender, size_t index) @@ -282,7 +282,7 @@ namespace MWGui if (index == MyGUI::ITEM_NONE) return; - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage67}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResolutionAccept); @@ -329,8 +329,8 @@ namespace MWGui void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); + std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); bool newState; if (_sender->castType()->getCaption() == on) { @@ -437,8 +437,8 @@ namespace MWGui void SettingsWindow::onShadersToggled(MyGUI::Widget* _sender) { - std::string on = mWindowManager.getGameSettingString("sOn", "On"); - std::string off = mWindowManager.getGameSettingString("sOff", "On"); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); + std::string off = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOff", "On"); std::string val = static_cast(_sender)->getCaption(); if (val == off) @@ -610,7 +610,7 @@ namespace MWGui void SettingsWindow::onResetDefaultBindings(MyGUI::Widget* _sender) { - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); dialog->open("#{sNotifyMessage66}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &SettingsWindow::onResetDefaultBindingsAccept); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index fc1ec9e365..292c1233de 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SETTINGS_H #define MWGUI_SETTINGS_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index d39ad6a5ae..9aa8074a24 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -48,7 +48,7 @@ namespace MWGui MyGUI::Button* toAdd = mSpellsView->createWidget( - (price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", + (price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, @@ -120,13 +120,13 @@ namespace MWGui { int price = *_sender->getUserData(); - if (mWindowManager.getInventoryWindow()->getPlayerGold()>=price) + if (MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()>=price) { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::CreatureStats& stats = MWWorld::Class::get(player).getCreatureStats(player); MWMechanics::Spells& spells = stats.getSpells(); spells.add (mSpellsWidgetMap.find(_sender)->second); - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); startSpellBuying(mPtr); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -135,12 +135,12 @@ namespace MWGui void SpellBuyingWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); } void SpellBuyingWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, @@ -150,8 +150,8 @@ namespace MWGui void SpellBuyingWindow::onReferenceUnavailable() { // remove both Spells and Dialogue (since you always trade with the NPC/creature that you have previously talked to) - mWindowManager.removeGuiMode(GM_SpellBuying); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void SpellBuyingWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index f9cda35df0..1418a9db52 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SpellBuyingWINDOW_H #define MWGUI_SpellBuyingWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" namespace MyGUI diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 592063a761..6fef91457f 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -303,38 +303,38 @@ namespace MWGui void SpellCreationDialog::onCancelButtonClicked (MyGUI::Widget* sender) { - mWindowManager.removeGuiMode (MWGui::GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (MWGui::GM_SpellCreation); } void SpellCreationDialog::onBuyButtonClicked (MyGUI::Widget* sender) { if (mEffects.size() <= 0) { - mWindowManager.messageBox ("#{sNotifyMessage30}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage30}"); return; } if (mNameEdit->getCaption () == "") { - mWindowManager.messageBox ("#{sNotifyMessage10}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage10}"); return; } if (mMagickaCost->getCaption() == "0") { - mWindowManager.messageBox ("#{sEnchantmentMenu8}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sEnchantmentMenu8}"); return; } - if (boost::lexical_cast(mPriceLabel->getCaption()) > mWindowManager.getInventoryWindow()->getPlayerGold()) + if (boost::lexical_cast(mPriceLabel->getCaption()) > MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) { - mWindowManager.messageBox ("#{sNotifyMessage18}"); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage18}"); return; } mSpell.mName = mNameEdit->getCaption(); - mWindowManager.getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-boost::lexical_cast(mPriceLabel->getCaption())); MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); @@ -347,7 +347,7 @@ namespace MWGui MWBase::Environment::get().getSoundManager()->playSound ("Item Gold Up", 1.0, 1.0); - mWindowManager.removeGuiMode (GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } void SpellCreationDialog::open() @@ -357,8 +357,8 @@ namespace MWGui void SpellCreationDialog::onReferenceUnavailable () { - mWindowManager.removeGuiMode (GM_Dialogue); - mWindowManager.removeGuiMode (GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_SpellCreation); } void SpellCreationDialog::notifyEffectsChanged () @@ -601,7 +601,6 @@ namespace MWGui Widgets::MWSpellEffectPtr effect = button->createWidget("MW_EffectImage", MyGUI::IntCoord(0,0,0,24), MyGUI::Align::Default); effect->setNeedMouseFocus (false); - effect->setWindowManager (MWBase::Environment::get().getWindowManager ()); effect->setSpellEffect (params); effect->setSize(effect->getRequestedWidth (), 24); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index 8f1c071804..facbdf5304 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SPELLCREATION_H #define MWGUI_SPELLCREATION_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" #include "list.hpp" #include "widgets.hpp" diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 021a849a08..257fab89d4 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -71,7 +71,7 @@ namespace MWGui void SpellWindow::onPinToggled() { - mWindowManager.setSpellVisibility(!mPinned); + MWBase::Environment::get().getWindowManager()->setSpellVisibility(!mPinned); } void SpellWindow::open() @@ -140,7 +140,7 @@ namespace MWGui { store.setSelectedEnchantItem(store.end()); spells.setSelectedSpell(""); - mWindowManager.unsetSelectedSpell(); + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); selectedItem = MWWorld::Ptr(); } } @@ -377,12 +377,12 @@ namespace MWGui action.execute (MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer ()); // since we changed equipping status, update the inventory window - mWindowManager.getInventoryWindow()->drawItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); } store.setSelectedEnchantItem(it); spells.setSelectedSpell(""); - mWindowManager.setSelectedEnchantItem(item); + MWBase::Environment::get().getWindowManager()->setSelectedEnchantItem(item); updateSpells(); } @@ -404,14 +404,14 @@ namespace MWGui if (spell->mData.mFlags & ESM::Spell::F_Always || spell->mData.mType == ESM::Spell::ST_Power) { - mWindowManager.messageBox("#{sDeleteSpellError}"); + MWBase::Environment::get().getWindowManager()->messageBox("#{sDeleteSpellError}"); } else { // ask for confirmation mSpellToDelete = spellId; - ConfirmationDialog* dialog = mWindowManager.getConfirmationDialog(); - std::string question = mWindowManager.getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); + ConfirmationDialog* dialog = MWBase::Environment::get().getWindowManager()->getConfirmationDialog(); + std::string question = MWBase::Environment::get().getWindowManager()->getGameSettingString("sQuestionDeleteSpell", "Delete %s?"); question = boost::str(boost::format(question) % spell->mName); dialog->open(question); dialog->eventOkClicked.clear(); @@ -423,7 +423,7 @@ namespace MWGui { spells.setSelectedSpell(spellId); store.setSelectedEnchantItem(store.end()); - mWindowManager.setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); + MWBase::Environment::get().getWindowManager()->setSelectedSpell(spellId, int(MWMechanics::getSpellSuccessChance(spellId, player))); } updateSpells(); @@ -454,7 +454,7 @@ namespace MWGui if (spells.getSelectedSpell() == mSpellToDelete) { spells.setSelectedSpell(""); - mWindowManager.unsetSelectedSpell(); + MWBase::Environment::get().getWindowManager()->unsetSelectedSpell(); } spells.remove(mSpellToDelete); diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index 1963d43463..b0994c5901 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_SPELLWINDOW_H #define MWGUI_SPELLWINDOW_H -#include "window_pinnable_base.hpp" +#include "windowpinnablebase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp new file mode 100644 index 0000000000..0e0676c2fb --- /dev/null +++ b/apps/openmw/mwgui/statswindow.cpp @@ -0,0 +1,580 @@ +#include "statswindow.hpp" + +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/windowmanager.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "tooltips.hpp" + + +using namespace MWGui; +const int StatsWindow::sLineHeight = 18; + +StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) + : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) + , mSkillView(NULL) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() + , mFactions() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() + , mChanged(true) +{ + setCoord(0,0,498, 342); + + const char *names[][2] = + { + { "Attrib1", "sAttributeStrength" }, + { "Attrib2", "sAttributeIntelligence" }, + { "Attrib3", "sAttributeWillpower" }, + { "Attrib4", "sAttributeAgility" }, + { "Attrib5", "sAttributeSpeed" }, + { "Attrib6", "sAttributeEndurance" }, + { "Attrib7", "sAttributePersonality" }, + { "Attrib8", "sAttributeLuck" }, + { 0, 0 } + }; + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (int i=0; names[i][0]; ++i) + { + setText (names[i][0], store.get().find (names[i][1])->getString()); + } + + getWidget(mSkillView, "SkillView"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); + + for (int i = 0; i < ESM::Skill::Length; ++i) + { + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); + } + + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); +} + +void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); +} + +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) ); + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); +} + +void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) +{ + MyGUI::ProgressPtr pt; + getWidget(pt, name); + pt->setProgressRange(max); + pt->setProgressPosition(val); + + std::stringstream out; + out << val << "/" << max; + setText(tname, out.str().c_str()); +} + +void StatsWindow::setPlayerName(const std::string& playerName) +{ + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); +} + +void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) +{ + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) + { + std::ostringstream valueString; + valueString << value.getModified(); + setText (id, valueString.str()); + + MyGUI::TextBox* box; + getWidget(box, id); + + if (value.getModified()>value.getBase()) + box->_setWidgetState("increased"); + else if (value.getModified()_setWidgetState("decreased"); + else + box->_setWidgetState("normal"); + + break; + } +} + +void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +{ + static const char *ids[] = + { + "HBar", "MBar", "FBar", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) + { + std::string id (ids[i]); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(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) +{ + if (id=="name") + setPlayerName (value); + else if (id=="race") + setText ("RaceText", value); + else if (id=="class") + setText ("ClassText", value); +} + +void StatsWindow::setValue (const std::string& id, int value) +{ + if (id=="level") + { + std::ostringstream text; + text << value; + setText("LevelText", text.str()); + } +} + +void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) +{ + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + + widget->setCaption(text); + widget->_setWidgetState(state); + } +} + +void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) +{ + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } + + updateSkillArea(); +} + +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); + + // level progress + MyGUI::Widget* levelWidget; + for (int i=0; i<2; ++i) + { + getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); + levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); + levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + } + + setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); + + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); + + if (mChanged) + updateSkillArea(); +} + +void StatsWindow::setFactions (const FactionList& factions) +{ + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } +} + +void StatsWindow::setExpelled (const std::set& expelled) +{ + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } +} + +void StatsWindow::setBirthSign (const std::string& signId) +{ + if (signId != mBirthSignId) + { + mBirthSignId = signId; + mChanged = true; + } +} + +void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::ImageBox* separator = mSkillView->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); + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); +} + +void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox* groupWidget = mSkillView->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); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; +} + +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 = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; +} + +MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillNameWidget; +} + +void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +{ + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; + + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); + assert(attr); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + } + + mSkillWidgetMap[skillId] = widget; + } +} + +void StatsWindow::updateSkillArea() +{ + mChanged = false; + + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); + mClientHeight = 0; + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + // race tooltip + const ESM::Race* playerRace = store.get().find(player->mRace); + + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + getWidget(raceWidget, "Race_str"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + + // class tooltip + MyGUI::Widget* classWidget; + + const ESM::Class *playerClass = + store.get().find(player->mClass); + + getWidget(classWidget, "ClassText"); + ToolTips::createClassToolTip(classWidget, *playerClass); + getWidget(classWidget, "Class_str"); + ToolTips::createClassToolTip(classWidget, *playerClass); + + if (!mFactions.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + { + const ESM::Faction *faction = + store.get().find(it->first); + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->mName; + + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else + { + text += std::string("\n#BF9959") + faction->mRanks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + } + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); + } + } + + if (!mBirthSignId.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); + MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); + + ToolTips::createBirthsignToolTip(w, mBirthSignId); + } + + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); + } + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); + } + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); +} + +void StatsWindow::onPinToggled() +{ + MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); +} diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp new file mode 100644 index 0000000000..93e26e063d --- /dev/null +++ b/apps/openmw/mwgui/statswindow.hpp @@ -0,0 +1,83 @@ +#ifndef MWGUI_STATS_WINDOW_H +#define MWGUI_STATS_WINDOW_H + +#include "../mwworld/esmstore.hpp" + +#include +#include +#include +#include + +#include "../mwmechanics/stat.hpp" +#include "windowpinnablebase.hpp" + +namespace MWGui +{ + class WindowManager; + + class StatsWindow : public WindowPinnableBase + { + public: + typedef std::map FactionList; + + typedef std::vector SkillList; + + StatsWindow(MWBase::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); + + /// Set value for the given ID. + void setValue (const std::string& id, const MWMechanics::Stat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const std::string& value); + void setValue (const std::string& id, int value); + void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); + + void configureSkills (const SkillList& major, const SkillList& minor); + void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } + void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } + void updateSkillArea(); + + 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); + 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); + + void setFactions (const FactionList& factions); + void setExpelled (const std::set& expelled); + void setBirthSign (const std::string &signId); + + void onWindowResize(MyGUI::Window* window); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + static const int sLineHeight; + + MyGUI::Widget* mLeftPane; + MyGUI::Widget* mRightPane; + + MyGUI::ScrollView* mSkillView; + int mLastPos, mClientHeight; + + SkillList mMajorSkills, mMinorSkills, mMiscSkills; + std::map > mSkillValues; + std::map mSkillWidgetMap; + std::map mFactionWidgetMap; + FactionList mFactions; ///< Stores a list of factions and the current rank + std::string mBirthSignId; + int mReputation, mBounty; + std::vector mSkillWidgets; //< Skills and other information + std::set mExpelled; + + bool mChanged; + + protected: + virtual void onPinToggled(); + }; +} +#endif diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp new file mode 100644 index 0000000000..071971befb --- /dev/null +++ b/apps/openmw/mwgui/textinput.cpp @@ -0,0 +1,70 @@ +#include "textinput.hpp" + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" + +using namespace MWGui; + +TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) + : WindowModal("openmw_text_input.layout", parWindowManager) +{ + // Centre dialog + center(); + + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); +} + +void TextInputDialog::setNextButtonShow(bool shown) +{ + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); +} + +void TextInputDialog::setTextLabel(const std::string &label) +{ + setText("LabelT", label); +} + +void TextInputDialog::open() +{ + WindowModal::open(); + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); +} + +// widget controls + +void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) +{ + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); +} + +void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) +{ + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); +} diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp new file mode 100644 index 0000000000..6b371bae74 --- /dev/null +++ b/apps/openmw/mwgui/textinput.hpp @@ -0,0 +1,33 @@ +#ifndef MWGUI_TEXT_INPUT_H +#define MWGUI_TEXT_INPUT_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class WindowManager; +} + +namespace MWGui +{ + class TextInputDialog : public WindowModal + { + public: + TextInputDialog(MWBase::WindowManager& parWindowManager); + + std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } + void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } + + void setNextButtonShow(bool shown); + void setTextLabel(const std::string &label); + virtual void open(); + + protected: + void onOkClicked(MyGUI::Widget* _sender); + void onTextAccepted(MyGUI::Edit* _sender); + + private: + MyGUI::EditBox* mTextEdit; + }; +} +#endif diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 9292e60e5c..7730019e83 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -12,7 +12,7 @@ #include "../mwworld/class.hpp" -#include "map_window.hpp" +#include "mapwindow.hpp" #include "widgets.hpp" #include "inventorywindow.hpp" @@ -22,7 +22,6 @@ using namespace MyGUI; ToolTips::ToolTips(MWBase::WindowManager* windowManager) : Layout("openmw_tooltips.layout") , mGameMode(true) - , mWindowManager(windowManager) , mFullHelp(false) , mEnabled(true) , mFocusToolTipX(0.0) @@ -81,9 +80,9 @@ void ToolTips::onFrame(float frameDuration) { const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - if (mWindowManager->getWorldMouseOver() && ((mWindowManager->getMode() == GM_Console) - || (mWindowManager->getMode() == GM_Container) - || (mWindowManager->getMode() == GM_Inventory))) + if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) { mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); @@ -93,7 +92,7 @@ void ToolTips::onFrame(float frameDuration) const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); IntSize tooltipSize; - if ((!objectclass.hasToolTip(mFocusObject))&&(mWindowManager->getMode() == GM_Console)) + if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) { setCoord(0, 0, 300, 300); mDynamicToolTipBox->setVisible(true); @@ -139,7 +138,7 @@ void ToolTips::onFrame(float frameDuration) mLastMouseX = mousePos.left; mLastMouseY = mousePos.top; - + if (mRemainingDelay > 0) return; @@ -167,8 +166,8 @@ void ToolTips::onFrame(float frameDuration) { return; } - - + + // special handling for markers on the local map: the tooltip should only be visible // if the marker is not hidden due to the fog of war. if (focus->getUserString ("IsMarker") == "true") @@ -190,11 +189,11 @@ void ToolTips::onFrame(float frameDuration) } else if (type == "AvatarItemSelection") { - MyGUI::IntCoord avatarPos = mWindowManager->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = mWindowManager->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); mFocusObject = item; if (!mFocusObject.isEmpty ()) @@ -346,7 +345,7 @@ void ToolTips::findImageExtension(std::string& image) } IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ +{ mDynamicToolTipBox->setVisible(true); std::string caption = info.caption; @@ -380,7 +379,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) setCoord(0, 0, 300, 300); const IntPoint padding(8, 8); - + const int maximumWidth = 500; const int imageCaptionHPadding = (caption != "" ? 8 : 0); @@ -424,7 +423,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr effectsWidget = effectArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEffectsWidget"); - effectsWidget->setWindowManager(mWindowManager); effectsWidget->setEffectList(info.effects); std::vector effectItems; @@ -444,7 +442,6 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); - enchantWidget->setWindowManager(mWindowManager); enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); std::vector enchantEffectItems; @@ -493,7 +490,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) (captionHeight-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); - + //if its too long we do hscroll with the caption if (captionSize.width > maximumWidth) { diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index da5a35221c..e4fcb310c8 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -82,8 +82,6 @@ namespace MWGui private: MyGUI::Widget* mDynamicToolTipBox; - MWBase::WindowManager* mWindowManager; - MWWorld::Ptr mFocusObject; void findImageExtension(std::string& image); @@ -96,9 +94,9 @@ namespace MWGui float mFocusToolTipX; float mFocusToolTipY; - + int mHorizontalScrollIndex; - + float mDelay; float mRemainingDelay; // remaining time until tooltip will show diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 81a29e69bd..718e6378bb 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -85,7 +85,7 @@ namespace MWGui mCurrentBalance = 0; mCurrentMerchantOffer = 0; - mWindowManager.getInventoryWindow()->startTrade(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->startTrade(); mBoughtItems.clear(); @@ -127,7 +127,7 @@ namespace MWGui { bool goldFound = false; MWWorld::Ptr gold; - MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); + MWWorld::ContainerStore& playerStore = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore(); for (MWWorld::ContainerStoreIterator it = playerStore.begin(); it != playerStore.end(); ++it) @@ -172,7 +172,7 @@ namespace MWGui MWBase::Environment::get().getWorld()->getStore().get(); // were there any items traded at all? - MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); + MWWorld::ContainerStore& playerBought = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getBoughtItems(); MWWorld::ContainerStore& merchantBought = getBoughtItems(); if (playerBought.begin() == playerBought.end() && merchantBought.begin() == merchantBought.end()) { @@ -183,7 +183,7 @@ namespace MWGui } // check if the player can afford this - if (mCurrentBalance < 0 && mWindowManager.getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) + if (mCurrentBalance < 0 && MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) { // user notification MWBase::Environment::get().getWindowManager()-> @@ -258,7 +258,7 @@ namespace MWGui // success! make the item transfer. transferBoughtItems(); - mWindowManager.getInventoryWindow()->transferBoughtItems(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->transferBoughtItems(); // add or remove gold from the player. if (mCurrentBalance != 0) @@ -267,17 +267,17 @@ namespace MWGui std::string sound = "Item Gold Up"; MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mWindowManager.removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { // i give you back your stuff! - returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); + returnBoughtItems(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getContainerStore()); // now gimme back my stuff! - mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mPtr).getContainerStore(mPtr)); - mWindowManager.removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); } void TradeWindow::onMaxSaleButtonClicked(MyGUI::Widget* _sender) @@ -321,7 +321,7 @@ namespace MWGui void TradeWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sYourGold} " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); if (mCurrentBalance > 0) { @@ -422,8 +422,8 @@ namespace MWGui 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); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } int TradeWindow::getMerchantGold() diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 2e05d03d51..111c0935fe 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -2,7 +2,7 @@ #define MWGUI_TRADEWINDOW_H #include "container.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 601b44d6c9..c2b543a4fd 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -40,7 +40,7 @@ namespace MWGui { mPtr = actor; - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); MWMechanics::NpcStats& npcStats = MWWorld::Class::get(actor).getNpcStats (actor); @@ -82,7 +82,7 @@ namespace MWGui int price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer (mPtr,pcStats.getSkill (bestSkills[i].first).getBase() * gmst.find("iTrainingMod")->getInt (),true); - std::string skin = (price > mWindowManager.getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; + std::string skin = (price > MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getPlayerGold ()) ? "SandTextGreyedOut" : "SandTextButton"; MyGUI::Button* button = mTrainingOptions->createWidget(skin, MyGUI::IntCoord(5, 5+i*18, mTrainingOptions->getWidth()-10, 18), MyGUI::Align::Default); @@ -102,12 +102,12 @@ namespace MWGui void TrainingWindow::onReferenceUnavailable () { - mWindowManager.removeGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Training); } void TrainingWindow::onCancelButtonClicked (MyGUI::Widget *sender) { - mWindowManager.removeGuiMode (GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); } void TrainingWindow::onTrainingSelected (MyGUI::Widget *sender) @@ -123,13 +123,13 @@ namespace MWGui int price = pcStats.getSkill (skillId).getBase() * store.get().find("iTrainingMod")->getInt (); price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - if (mWindowManager.getInventoryWindow()->getPlayerGold()getInventoryWindow()->getPlayerGold()messageBox ("#{sServiceTrainingWords}"); return; } @@ -141,11 +141,11 @@ namespace MWGui pcStats.increaseSkill (skillId, *class_, true); // remove gold - mWindowManager.getTradeWindow()->addOrRemoveGold(-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-price); // go back to game mode - mWindowManager.removeGuiMode (GM_Training); - mWindowManager.removeGuiMode (GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Training); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Dialogue); // advance time MWBase::Environment::get().getWorld ()->advanceTime (2); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index f2ef1714ee..d6be60ae67 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_TRAININGWINDOW_H #define MWGUI_TRAININGWINDOW_H -#include "window_base.hpp" +#include "windowbase.hpp" #include "referenceinterface.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 465f588b8a..b710171669 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -71,7 +71,7 @@ namespace MWGui price = MWBase::Environment::get().getMechanicsManager()->getBarterOffer(mPtr,price,true); - MyGUI::Button* toAdd = mDestinationsView->createWidget((price>mWindowManager.getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); + MyGUI::Button* toAdd = mDestinationsView->createWidget((price>MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold()) ? "SandTextGreyedOut" : "SandTextButton", 0, mCurrentY, 200, sLineHeight, MyGUI::Align::Default); mCurrentY += sLineHeight; if(interior) toAdd->setUserString("interior","y"); @@ -129,10 +129,10 @@ namespace MWGui int price; iss >> price; - if (mWindowManager.getInventoryWindow()->getPlayerGold()getInventoryWindow()->getPlayerGold()addOrRemoveGold (-price); + MWBase::Environment::get().getWindowManager()->getTradeWindow ()->addOrRemoveGold (-price); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -156,20 +156,20 @@ namespace MWGui MWBase::Environment::get().getWorld()->advanceTime(time); } MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); - mWindowManager.removeGuiMode(GM_Travel); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(1); } void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { - mWindowManager.removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); } void TravelWindow::updateLabels() { - mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + mPlayerGold->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold())); mPlayerGold->setCoord(8, mPlayerGold->getTop(), mPlayerGold->getTextSize().width, @@ -178,8 +178,8 @@ namespace MWGui void TravelWindow::onReferenceUnavailable() { - mWindowManager.removeGuiMode(GM_Travel); - mWindowManager.removeGuiMode(GM_Dialogue); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); } void TravelWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index cc3d6a31f7..61b724910c 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -2,7 +2,7 @@ #define MWGUI_TravelWINDOW_H #include "container.hpp" -#include "window_base.hpp" +#include "windowbase.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 09eb5c914e..69dfa10b4d 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -75,7 +75,7 @@ namespace MWGui { if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) { - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } int canRest = MWBase::Environment::get().getWorld ()->canRest (); @@ -83,8 +83,8 @@ namespace MWGui if (canRest == 2) { // resting underwater or mid-air not allowed - mWindowManager.messageBox ("#{sNotifyMessage1}"); - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage1}"); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } setCanRest(canRest == 0); @@ -212,7 +212,7 @@ namespace MWGui void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) { - mWindowManager.popGuiMode (); + MWBase::Environment::get().getWindowManager()->popGuiMode (); } void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) @@ -263,8 +263,8 @@ namespace MWGui { MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); mProgressBar.setVisible (false); - mWindowManager.removeGuiMode (GM_Rest); - mWindowManager.removeGuiMode (GM_RestBed); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); + MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); mWaiting = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -273,7 +273,7 @@ namespace MWGui // trigger levelup if possible if (mSleeping && pcstats.getLevelProgress () >= 10) { - mWindowManager.pushGuiMode (GM_Levelup); + MWBase::Environment::get().getWindowManager()->pushGuiMode (GM_Levelup); } } diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index c102d0fc67..4510e665b3 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -1,7 +1,7 @@ #ifndef MWGUI_WAIT_DIALOG_H #define MWGUI_WAIT_DIALOG_H -#include "window_base.hpp" +#include "windowbase.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e822e047ea..3801ae6f7a 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -218,8 +218,7 @@ void MWAttribute::initialiseOverride() /* MWSpell */ MWSpell::MWSpell() - : mWindowManager(NULL) - , mSpellNameWidget(NULL) + : mSpellNameWidget(NULL) { } @@ -242,7 +241,6 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::W for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - effect->setWindowManager(mWindowManager); SpellEffectParams params; params.mEffectID = it->mEffectID; params.mSkill = it->mSkill; @@ -262,7 +260,7 @@ void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::W void MWSpell::updateWidgets() { - if (mSpellNameWidget && mWindowManager) + if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) { const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); @@ -289,8 +287,7 @@ MWSpell::~MWSpell() /* MWEffectList */ MWEffectList::MWEffectList() - : mWindowManager(NULL) - , mEffectList(0) + : mEffectList(0) { } @@ -311,7 +308,6 @@ void MWEffectList::createEffectWidgets(std::vector &effects, MyG it != mEffectList.end(); ++it) { effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - effect->setWindowManager(mWindowManager); it->mIsConstant = (flags & EF_Constant) || it->mIsConstant; it->mNoTarget = (flags & EF_NoTarget) || it->mNoTarget; effect->setSpellEffect(*it); @@ -378,8 +374,7 @@ SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) /* MWSpellEffect */ MWSpellEffect::MWSpellEffect() - : mWindowManager(NULL) - , mImageWidget(NULL) + : mImageWidget(NULL) , mTextWidget(NULL) , mRequestedWidth(0) { @@ -409,22 +404,22 @@ void MWSpellEffect::updateWidgets() assert(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 pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; + std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); + std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); - std::string spellLine = mWindowManager->getGameSettingString(effectIDStr, ""); + std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); } if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { - spellLine += " " + mWindowManager->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); } if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) @@ -442,7 +437,7 @@ void MWSpellEffect::updateWidgets() { if (mEffectParams.mDuration >= 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { - spellLine += " " + mWindowManager->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); } if (mEffectParams.mArea > 0) @@ -453,13 +448,13 @@ void MWSpellEffect::updateWidgets() // potions have no target if (!mEffectParams.mNoTarget) { - std::string on = mWindowManager->getGameSettingString("sonword", ""); + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); if (mEffectParams.mRange == ESM::RT_Self) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeSelf", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); else if (mEffectParams.mRange == ESM::RT_Touch) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTouch", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); else if (mEffectParams.mRange == ESM::RT_Target) - spellLine += " " + on + " " + mWindowManager->getGameSettingString("sRangeTarget", ""); + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 784537c42a..26ca750667 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -94,7 +94,6 @@ namespace MWGui typedef MWMechanics::Stat SkillValue; - void setWindowManager(MWBase::WindowManager *m) { mManager = m; } /// \todo remove void setSkillId(ESM::Skill::SkillEnum skillId); void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); @@ -138,7 +137,6 @@ namespace MWGui typedef MWMechanics::Stat AttributeValue; - void setWindowManager(MWBase::WindowManager *m) { mManager = m; } void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); @@ -185,7 +183,6 @@ namespace MWGui typedef MWMechanics::Stat SpellValue; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellId(const std::string &id); /** @@ -207,7 +204,6 @@ namespace MWGui private: void updateWidgets(); - MWBase::WindowManager* mWindowManager; std::string mId; MyGUI::TextBox* mSpellNameWidget; }; @@ -227,7 +223,6 @@ namespace MWGui EF_Constant = 0x02 // constant effect means that duration will not be displayed }; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setEffectList(const SpellEffectList& list); static SpellEffectList effectListFromESM(const ESM::EffectList* effects); @@ -249,7 +244,6 @@ namespace MWGui private: void updateWidgets(); - MWBase::WindowManager* mWindowManager; SpellEffectList mEffectList; }; typedef MWEffectList* MWEffectListPtr; @@ -262,7 +256,6 @@ namespace MWGui typedef ESM::ENAMstruct SpellEffectValue; - void setWindowManager(MWBase::WindowManager* parWindowManager) { mWindowManager = parWindowManager; } void setSpellEffect(const SpellEffectParams& params); int getRequestedWidth() const { return mRequestedWidth; } @@ -276,7 +269,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager* mWindowManager; SpellEffectParams mEffectParams; MyGUI::ImageBox* mImageWidget; MyGUI::TextBox* mTextWidget; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp new file mode 100644 index 0000000000..cb3d4ea8c8 --- /dev/null +++ b/apps/openmw/mwgui/windowbase.cpp @@ -0,0 +1,54 @@ +#include "windowbase.hpp" + +#include + +#include "../mwbase/windowmanager.hpp" + +using namespace MWGui; + +WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : Layout(parLayout) +{ +} + +void WindowBase::setVisible(bool visible) +{ + bool wasVisible = mMainWidget->getVisible(); + mMainWidget->setVisible(visible); + + if (visible) + open(); + else if (wasVisible && !visible) + close(); +} + +void WindowBase::center() +{ + // Centre dialog + + // 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; + mMainWidget->setCoord(coord); +} + +WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager) +{ +} + +void WindowModal::open() +{ + MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); +} + +void WindowModal::close() +{ + MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); +} diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp new file mode 100644 index 0000000000..a2cb731fee --- /dev/null +++ b/apps/openmw/mwgui/windowbase.hpp @@ -0,0 +1,47 @@ +#ifndef MWGUI_WINDOW_BASE_H +#define MWGUI_WINDOW_BASE_H + +#include + +namespace MWBase +{ + class WindowManager; +} + +namespace MWGui +{ + class WindowManager; + + class WindowBase: public OEngine::GUI::Layout + { + public: + WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + + // Events + typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; + + virtual void open() {} + virtual void close () {} + virtual void setVisible(bool visible); + void center(); + + /** Event : Dialog finished, OK button clicked.\n + signature : void method()\n + */ + EventHandle_WindowBase eventDone; + }; + + + /* + * "Modal" windows cause the rest of the interface to be unaccessible while they are visible + */ + class WindowModal : public WindowBase + { + public: + WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + virtual void open(); + virtual void close(); + }; +} + +#endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a66..bcde82e966 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -21,12 +21,12 @@ #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" -#include "text_input.hpp" +#include "textinput.hpp" #include "review.hpp" #include "dialogue.hpp" -#include "dialogue_history.hpp" -#include "map_window.hpp" -#include "stats_window.hpp" +#include "dialoguehistory.hpp" +#include "mapwindow.hpp" +#include "statswindow.hpp" #include "messagebox.hpp" #include "container.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp new file mode 100644 index 0000000000..54ed082cf9 --- /dev/null +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -0,0 +1,28 @@ +#include "windowpinnablebase.hpp" + +#include "../mwbase/windowmanager.hpp" + +#include "exposedwindow.hpp" + +using namespace MWGui; + +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) + : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) +{ + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); + + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); +} + +void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) +{ + mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + + onPinToggled(); +} diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp new file mode 100644 index 0000000000..657e8142f1 --- /dev/null +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -0,0 +1,28 @@ +#ifndef MWGUI_WINDOW_PINNABLE_BASE_H +#define MWGUI_WINDOW_PINNABLE_BASE_H + +#include "windowbase.hpp" + +namespace MWGui +{ + class WindowManager; + + class WindowPinnableBase: public WindowBase + { + public: + WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + bool pinned() { return mPinned; } + + private: + void onPinButtonClicked(MyGUI::Widget* _sender); + + protected: + virtual void onPinToggled() = 0; + + MyGUI::Widget* mPinButton; + bool mPinned; + bool mVisible; + }; +} + +#endif From ad49d1ecab8be0fdd863a5f747f5a680bf1fdc5a Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 15:24:20 +0200 Subject: [PATCH 0383/1537] Sixth minor fix --- apps/openmw/mwclass/armor.cpp | 6 +++--- apps/openmw/mwclass/armor.hpp | 2 +- apps/openmw/mwclass/clothing.cpp | 6 +++--- apps/openmw/mwclass/clothing.hpp | 2 +- apps/openmw/mwclass/weapon.cpp | 18 +++++++++--------- apps/openmw/mwclass/weapon.hpp | 2 +- apps/openmw/mwworld/actionequip.cpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 2 +- apps/openmw/mwworld/inventorystore.cpp | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index a14b2667e1..d257c87619 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,12 +292,12 @@ namespace MWClass ref->mBase = record; } - int Armor::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); // slots that this item can be equipped in - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::string npcRace = npc.get()->mBase->mRace; @@ -309,7 +309,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = item.get()->mBase->mParts.mParts; + std::vector parts = ptr.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 96c72848cc..1b99e51331 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 58c4a2c5c6..b4e6e61f65 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,10 +238,10 @@ namespace MWClass ref->mBase = record; } - int Clothing::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); std::string npcRace = npc.get()->mBase->mRace; @@ -253,7 +253,7 @@ namespace MWClass const ESM::Race* race = MWBase::Environment::get().getWorld()->getStore().get().find(npcRace); if(race->mData.mFlags & ESM::Race::Beast) { - std::vector parts = item.get()->mBase->mParts.mParts; + std::vector parts = ptr.get()->mBase->mParts.mParts; if(*slot == MWWorld::InventoryStore::Slot_Helmet) { diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index eb8d801996..71e01e8187 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,7 +61,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index a0cacaf6bd..e534a65c2a 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,9 +384,9 @@ namespace MWClass ref->mBase = record; } - int Weapon::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - std::pair, bool> slots = MWWorld::Class::get(item).getEquipmentSlots(item); + std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); // equip the item in the first free slot for (std::vector::const_iterator slot=slots.first.begin(); @@ -394,13 +394,13 @@ namespace MWClass { if(*slot == MWWorld::InventoryStore::Slot_CarriedRight) { - if(item.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || - item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || - item.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || - item.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || - item.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || - item.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) + if(ptr.get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || + ptr.get()->mBase->mData.mType == ESM::Weapon::BluntTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::SpearTwoWide || + ptr.get()->mBase->mData.mType == ESM::Weapon::AxeTwoHand || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || + ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { return 2; } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 01686b09cc..6c3f32abef 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,7 +67,7 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp index fd35d0dd3c..84d1a3d158 100644 --- a/apps/openmw/mwworld/actionequip.cpp +++ b/apps/openmw/mwworld/actionequip.cpp @@ -21,7 +21,7 @@ namespace MWWorld MWWorld::Ptr object = getTarget(); MWWorld::InventoryStore& invStore = MWWorld::Class::get(actor).getInventoryStore(actor); - switch(MWWorld::Class::get (object).canBeEquipped (actor, object)) + switch(MWWorld::Class::get (object).canBeEquipped (object, actor)) { case 0: return; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index a0067f5d2e..d7ff350141 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -259,7 +259,7 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - int Class::canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const + int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { return 1; } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 362a8bc9ca..484004aca5 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -242,7 +242,7 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &npc, const MWWorld::Ptr &item) const; + virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. virtual Ptr diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 782e3f920f..5495d6a021 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - switch(MWWorld::Class::get (test).canBeEquipped (npc, test)) + switch(MWWorld::Class::get (test).canBeEquipped (test, npc)) { case 0: continue; From d768f6b57e2e4b992861a18dedf9e39c6e79b702 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 13:05:15 -0400 Subject: [PATCH 0384/1537] Deleted *_* files in MwGui, builds. --- apps/openmw/CMakeLists.txt | 6 +- apps/openmw/mwgui/dialogue_history.cpp | 76 --- apps/openmw/mwgui/dialogue_history.hpp | 19 - apps/openmw/mwgui/map_window.cpp | 446 ---------------- apps/openmw/mwgui/map_window.hpp | 107 ---- apps/openmw/mwgui/stats_window.cpp | 580 --------------------- apps/openmw/mwgui/stats_window.hpp | 83 --- apps/openmw/mwgui/text_input.cpp | 69 --- apps/openmw/mwgui/text_input.hpp | 36 -- apps/openmw/mwgui/window_base.cpp | 55 -- apps/openmw/mwgui/window_base.hpp | 51 -- apps/openmw/mwgui/window_pinnable_base.cpp | 28 - apps/openmw/mwgui/window_pinnable_base.hpp | 28 - 13 files changed, 3 insertions(+), 1581 deletions(-) delete mode 100644 apps/openmw/mwgui/dialogue_history.cpp delete mode 100644 apps/openmw/mwgui/dialogue_history.hpp delete mode 100644 apps/openmw/mwgui/map_window.cpp delete mode 100644 apps/openmw/mwgui/map_window.hpp delete mode 100644 apps/openmw/mwgui/stats_window.cpp delete mode 100644 apps/openmw/mwgui/stats_window.hpp delete mode 100644 apps/openmw/mwgui/text_input.cpp delete mode 100644 apps/openmw/mwgui/text_input.hpp delete mode 100644 apps/openmw/mwgui/window_base.cpp delete mode 100644 apps/openmw/mwgui/window_base.hpp delete mode 100644 apps/openmw/mwgui/window_pinnable_base.cpp delete mode 100644 apps/openmw/mwgui/window_pinnable_base.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8a0030be42..b3c3f4134c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -24,9 +24,9 @@ add_openmw_dir (mwinput ) add_openmw_dir (mwgui - text_input widgets race class birth review windowmanagerimp console dialogue - dialogue_history window_base stats_window messagebox journalwindow charactercreation - map_window window_pinnable_base tooltips scrollwindow bookwindow list + textinput widgets race class birth review windowmanagerimp console dialogue + dialoguehistory windowbase statswindow messagebox journalwindow charactercreation + mapwindow windowpinnablebase tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog diff --git a/apps/openmw/mwgui/dialogue_history.cpp b/apps/openmw/mwgui/dialogue_history.cpp deleted file mode 100644 index 13f72545e2..0000000000 --- a/apps/openmw/mwgui/dialogue_history.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include "dialogue_history.hpp" - -#include "../mwbase/windowmanager.hpp" - -#include "widgets.hpp" - -#include "../mwworld/esmstore.hpp" - -#include -#include - -#include -#include - -using namespace MWGui; -using namespace Widgets; - -MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) -{ - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::TextIterator iterator(getCaption()); - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if (pos < _pos) - continue; - else if (pos == _pos) - break; - } - return colour; -} - -MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) -{ - bool breakOnNext = false; - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::UString colour2 = colour; - MyGUI::TextIterator iterator(getCaption()); - MyGUI::TextIterator col_start = iterator; - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if(colour != colour2) - { - if(breakOnNext) - { - return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); - } - col_start = iterator; - colour2 = colour; - } - if (pos < _pos) - continue; - else if (pos == _pos) - { - breakOnNext = true; - } - } - return ""; -} - -void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) -{ - MyGUI::UString head("\n#D8C09A"); - head.append(parText); - head.append("#B29154\n"); - addText(head); -} - -void DialogueHistory::addDialogText(const MyGUI::UString& parText) -{ - addText(parText); - addText("\n"); -} diff --git a/apps/openmw/mwgui/dialogue_history.hpp b/apps/openmw/mwgui/dialogue_history.hpp deleted file mode 100644 index c37504af77..0000000000 --- a/apps/openmw/mwgui/dialogue_history.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef MWGUI_DIALOGE_HISTORY_H -#define MWGUI_DIALOGE_HISTORY_H -#include - -namespace MWGui -{ - class DialogueHistory : public MyGUI::EditBox - { - MYGUI_RTTI_DERIVED( DialogueHistory ) - public: - Widget* getClient() { return mClient; } - MyGUI::UString getColorAtPos(size_t _pos); - MyGUI::UString getColorTextAt(size_t _pos); - void addDialogHeading(const MyGUI::UString& parText); - void addDialogText(const MyGUI::UString& parText); - }; -} -#endif - diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp deleted file mode 100644 index d0f3f921e5..0000000000 --- a/apps/openmw/mwgui/map_window.cpp +++ /dev/null @@ -1,446 +0,0 @@ -#include "map_window.hpp" - -#include - -#include -#include -#include - -#include - -#include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" -#include "../mwworld/player.hpp" - -#include "../mwrender/globalmap.hpp" - -#include "widgets.hpp" - -using namespace MWGui; - -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mMapDragAndDrop(false) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) - , mCompass(NULL) -{ -} - -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) -{ - 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 + (-1*(my-1))); - MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } - notifyMapChanged (); -} - -void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -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 - - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } - - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); - - 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); - else - box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) - { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); - } - else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); - } - - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); - } - - - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; - - // fog of war - 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; - - notifyPlayerUpdate (); - - 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; - - notifyPlayerUpdate (); - - 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; -} - -// ------------------------------------------------------------------------------------------ - -MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) - , mGlobal(false) -{ - setCoord(500,0,320,300); - - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mGlobalMapImage, "GlobalMapImage"); - getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); - getWidget(mPlayerArrowLocal, "CompassLocal"); - getWidget(mPlayerArrowGlobal, "CompassGlobal"); - - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - - mGlobalMap->setVisible (false); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing("#{sWorld}"); - - getWidget(mEventBoxGlobal, "EventBoxGlobal"); - mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - getWidget(mEventBoxLocal, "EventBoxLocal"); - mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); -} - -MapWindow::~MapWindow() -{ - delete mGlobalMapRender; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - setTitle("#{sCell=" + cellName + "}"); -} - -void MapWindow::addVisitedLocation(const std::string& name, int x, int y) -{ - float worldX, worldY; - mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); - - MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+6, - worldY * mGlobalMapRender->getHeight()+6, - 12, 12); - - - static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); - ++_counter; - - markerWidget = mEventBoxGlobal->createWidget("", - widgetCoord, MyGUI::Align::Default); - markerWidget->setNeedMouseFocus (true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); -} - -void MapWindow::cellExplored(int x, int y) -{ - mGlobalMapRender->exploreCell(x,y); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - - if (!mGlobal) - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - else - mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); - - - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); - - if (mGlobal) - globalMapUpdatePlayer (); -} - -void MapWindow::onPinToggled() -{ - mWindowManager.setMinimapVisibility(!mPinned); -} - -void MapWindow::open() -{ - mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - - for (unsigned int i=0; igetChildCount (); ++i) - { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); - } - - globalMapUpdatePlayer(); - - mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); -} - -void MapWindow::globalMapUpdatePlayer () -{ - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? - if (MWBase::Environment::get().getWorld ()->isCellExterior ()) - { - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); - - MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); - MyGUI::RotatingSkin* rotatingSubskin = main->castType(); - rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(dir.x, dir.y); - rotatingSubskin->setAngle(angle); - - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); - } -} - -void MapWindow::notifyPlayerUpdate () -{ - globalMapUpdatePlayer (); -} - -void MapWindow::notifyMapChanged () -{ - // workaround to prevent the map from drawing on top of the button - MyGUI::IntCoord oldCoord = mButton->getCoord (); - MyGUI::Gui::getInstance().destroyWidget (mButton); - mButton = mMainWidget->createWidget("MW_Button", - oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); - mButton->setProperty ("ExpandDirection", "Left"); - - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); -} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp deleted file mode 100644 index 39770a7a26..0000000000 --- a/apps/openmw/mwgui/map_window.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef MWGUI_MAPWINDOW_H -#define MWGUI_MAPWINDOW_H - -#include "window_pinnable_base.hpp" - -namespace MWRender -{ - class GlobalMap; -} - -namespace MWGui -{ - class LocalMapBase - { - public: - LocalMapBase(); - 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(); - - struct MarkerPosition - { - bool interior; - int cellX; - int cellY; - float nX; - float nY; - }; - - protected: - 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(); - - void onMarkerFocused(MyGUI::Widget* w1, MyGUI::Widget* w2); - void onMarkerUnfocused(MyGUI::Widget* w1, MyGUI::Widget* w2); - - virtual void notifyPlayerUpdate() {} - virtual void notifyMapChanged() {} - - OEngine::GUI::Layout* mLayout; - - bool mMapDragAndDrop; - - float mLastPositionX; - float mLastPositionY; - float mLastDirectionX; - float mLastDirectionY; - }; - - class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase - { - public: - MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); - virtual ~MapWindow(); - - void setCellName(const std::string& cellName); - - void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map - void cellExplored(int x, int y); - - virtual void open(); - - private: - void onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); - void onWorldButtonClicked(MyGUI::Widget* _sender); - - void globalMapUpdatePlayer(); - - MyGUI::ScrollView* mGlobalMap; - MyGUI::ImageBox* mGlobalMapImage; - MyGUI::ImageBox* mGlobalMapOverlay; - MyGUI::ImageBox* mPlayerArrowLocal; - MyGUI::ImageBox* mPlayerArrowGlobal; - MyGUI::Button* mButton; - MyGUI::IntPoint mLastDragPos; - bool mGlobal; - - MyGUI::Button* mEventBoxGlobal; - MyGUI::Button* mEventBoxLocal; - - MWRender::GlobalMap* mGlobalMapRender; - - protected: - virtual void onPinToggled(); - - virtual void notifyPlayerUpdate(); - virtual void notifyMapChanged(); - - }; -} -#endif diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp deleted file mode 100644 index 0678e98919..0000000000 --- a/apps/openmw/mwgui/stats_window.cpp +++ /dev/null @@ -1,580 +0,0 @@ -#include "stats_window.hpp" - -#include -#include -#include - -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" - -#include "../mwmechanics/npcstats.hpp" - -#include "tooltips.hpp" - - -using namespace MWGui; -const int StatsWindow::sLineHeight = 18; - -StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) - , mSkillView(NULL) - , mClientHeight(0) - , mMajorSkills() - , mMinorSkills() - , mMiscSkills() - , mSkillValues() - , mSkillWidgetMap() - , mFactionWidgetMap() - , mFactions() - , mBirthSignId() - , mReputation(0) - , mBounty(0) - , mSkillWidgets() - , mChanged(true) -{ - setCoord(0,0,498, 342); - - const char *names[][2] = - { - { "Attrib1", "sAttributeStrength" }, - { "Attrib2", "sAttributeIntelligence" }, - { "Attrib3", "sAttributeWillpower" }, - { "Attrib4", "sAttributeAgility" }, - { "Attrib5", "sAttributeSpeed" }, - { "Attrib6", "sAttributeEndurance" }, - { "Attrib7", "sAttributePersonality" }, - { "Attrib8", "sAttributeLuck" }, - { 0, 0 } - }; - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (int i=0; names[i][0]; ++i) - { - setText (names[i][0], store.get().find (names[i][1])->getString()); - } - - getWidget(mSkillView, "SkillView"); - getWidget(mLeftPane, "LeftPane"); - getWidget(mRightPane, "RightPane"); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); - } - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); -} - -void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); -} - -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) ); - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) -{ - MyGUI::ProgressPtr pt; - getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); - - std::stringstream out; - out << val << "/" << max; - setText(tname, out.str().c_str()); -} - -void StatsWindow::setPlayerName(const std::string& playerName) -{ - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; - - for (int i=0; ids[i]; ++i) - if (ids[i]==id) - { - std::ostringstream valueString; - valueString << value.getModified(); - setText (id, valueString.str()); - - MyGUI::TextBox* box; - getWidget(box, id); - - if (value.getModified()>value.getBase()) - box->_setWidgetState("increased"); - else if (value.getModified()_setWidgetState("decreased"); - else - box->_setWidgetState("normal"); - - break; - } -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = - { - "HBar", "MBar", "FBar", - 0 - }; - - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) - { - std::string id (ids[i]); - setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(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) -{ - if (id=="name") - setPlayerName (value); - else if (id=="race") - setText ("RaceText", value); - else if (id=="class") - setText ("ClassText", value); -} - -void StatsWindow::setValue (const std::string& id, int value) -{ - if (id=="level") - { - std::ostringstream text; - text << value; - setText("LevelText", text.str()); - } -} - -void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - mSkillValues[parSkill] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } -} - -void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); - } - - updateSkillArea(); -} - -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); - - // level progress - MyGUI::Widget* levelWidget; - for (int i=0; i<2; ++i) - { - getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); - } - - setFactions(PCstats.getFactionRanks()); - setExpelled(PCstats.getExpelled ()); - - const std::string &signId = - MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); - - setBirthSign(signId); - setReputation (PCstats.getReputation ()); - setBounty (PCstats.getBounty ()); - - if (mChanged) - updateSkillArea(); -} - -void StatsWindow::setFactions (const FactionList& factions) -{ - if (mFactions != factions) - { - mFactions = factions; - mChanged = true; - } -} - -void StatsWindow::setExpelled (const std::set& expelled) -{ - if (mExpelled != expelled) - { - mExpelled = expelled; - mChanged = true; - } -} - -void StatsWindow::setBirthSign (const std::string& signId) -{ - if (signId != mBirthSignId) - { - mBirthSignId = signId; - mChanged = true; - } -} - -void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->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); - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->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); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -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 = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillNameWidget; -} - -void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); - } - - addGroup(mWindowManager.getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) - { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; - - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); - - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; - - const ESM::Attribute* attr = - esmStore.get().find(skill->mData.mAttribute); - 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), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); - } - - mSkillWidgetMap[skillId] = widget; - } -} - -void StatsWindow::updateSkillArea() -{ - mChanged = false; - - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillWidgets.clear(); - - mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); - mClientHeight = 0; - - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - - MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::ESMStore &store = world->getStore(); - const ESM::NPC *player = - world->getPlayer().getPlayer().get()->mBase; - - // race tooltip - const ESM::Race* playerRace = store.get().find(player->mRace); - - MyGUI::Widget* raceWidget; - getWidget(raceWidget, "RaceText"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - getWidget(raceWidget, "Race_str"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - - // class tooltip - MyGUI::Widget* classWidget; - - const ESM::Class *playerClass = - store.get().find(player->mClass); - - getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, *playerClass); - getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, *playerClass); - - if (!mFactions.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - std::set& expelled = PCstats.getExpelled (); - - addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) - { - const ESM::Faction *faction = - store.get().find(it->first); - MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); - - std::string text; - - text += std::string("#DDC79E") + faction->mName; - - if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; - else - { - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - - if (it->second < 9) - { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) - { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; - if (i<5) - text += ", "; - } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); - } - } - - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "TextToolTip"); - w->setUserString("Caption_Text", text); - } - } - - if (!mBirthSignId.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = - store.get().find(mBirthSignId); - MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); - - ToolTips::createBirthsignToolTip(w, mBirthSignId); - } - - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); - } - - addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); - } - - mClientHeight = coord1.top; - - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::onPinToggled() -{ - mWindowManager.setHMSVisibility(!mPinned); -} diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp deleted file mode 100644 index 3befc1f002..0000000000 --- a/apps/openmw/mwgui/stats_window.hpp +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef MWGUI_STATS_WINDOW_H -#define MWGUI_STATS_WINDOW_H - -#include "../mwworld/esmstore.hpp" - -#include -#include -#include -#include - -#include "../mwmechanics/stat.hpp" -#include "window_pinnable_base.hpp" - -namespace MWGui -{ - class WindowManager; - - class StatsWindow : public WindowPinnableBase - { - public: - typedef std::map FactionList; - - typedef std::vector SkillList; - - StatsWindow(MWBase::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); - - /// Set value for the given ID. - void setValue (const std::string& id, const MWMechanics::Stat& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setValue (const std::string& id, const std::string& value); - void setValue (const std::string& id, int value); - void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); - - void configureSkills (const SkillList& major, const SkillList& minor); - void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } - void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } - void updateSkillArea(); - - 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); - 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); - - void setFactions (const FactionList& factions); - void setExpelled (const std::set& expelled); - void setBirthSign (const std::string &signId); - - void onWindowResize(MyGUI::Window* window); - void onMouseWheel(MyGUI::Widget* _sender, int _rel); - - static const int sLineHeight; - - MyGUI::Widget* mLeftPane; - MyGUI::Widget* mRightPane; - - MyGUI::ScrollView* mSkillView; - int mLastPos, mClientHeight; - - SkillList mMajorSkills, mMinorSkills, mMiscSkills; - std::map > mSkillValues; - std::map mSkillWidgetMap; - std::map mFactionWidgetMap; - FactionList mFactions; ///< Stores a list of factions and the current rank - std::string mBirthSignId; - int mReputation, mBounty; - std::vector mSkillWidgets; //< Skills and other information - std::set mExpelled; - - bool mChanged; - - protected: - virtual void onPinToggled(); - }; -} -#endif diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp deleted file mode 100644 index ee9144be68..0000000000 --- a/apps/openmw/mwgui/text_input.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "text_input.hpp" - -#include "../mwbase/windowmanager.hpp" - -using namespace MWGui; - -TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_text_input.layout", parWindowManager) -{ - // Centre dialog - center(); - - getWidget(mTextEdit, "TextEdit"); - mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -void TextInputDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(mWindowManager.getGameSettingString("sNext", "")); - else - okButton->setCaption(mWindowManager.getGameSettingString("sOK", "")); -} - -void TextInputDialog::setTextLabel(const std::string &label) -{ - setText("LabelT", label); -} - -void TextInputDialog::open() -{ - WindowModal::open(); - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -// widget controls - -void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if (mTextEdit->getCaption() == "") - { - mWindowManager.messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} - -void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) -{ - if (mTextEdit->getCaption() == "") - { - mWindowManager.messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} diff --git a/apps/openmw/mwgui/text_input.hpp b/apps/openmw/mwgui/text_input.hpp deleted file mode 100644 index 29de7388b2..0000000000 --- a/apps/openmw/mwgui/text_input.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MWGUI_TEXT_INPUT_H -#define MWGUI_TEXT_INPUT_H - -#include "window_base.hpp" - -namespace MWGui -{ - class WindowManager; -} - -/* - */ - -namespace MWGui -{ - class TextInputDialog : public WindowModal - { - public: - TextInputDialog(MWBase::WindowManager& parWindowManager); - - std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } - void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } - - void setNextButtonShow(bool shown); - void setTextLabel(const std::string &label); - virtual void open(); - - protected: - void onOkClicked(MyGUI::Widget* _sender); - void onTextAccepted(MyGUI::Edit* _sender); - - private: - MyGUI::EditBox* mTextEdit; - }; -} -#endif diff --git a/apps/openmw/mwgui/window_base.cpp b/apps/openmw/mwgui/window_base.cpp deleted file mode 100644 index 38bee9ea30..0000000000 --- a/apps/openmw/mwgui/window_base.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "window_base.hpp" - -#include - -#include "../mwbase/windowmanager.hpp" - -using namespace MWGui; - -WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : Layout(parLayout) - , mWindowManager(parWindowManager) -{ -} - -void WindowBase::setVisible(bool visible) -{ - bool wasVisible = mMainWidget->getVisible(); - mMainWidget->setVisible(visible); - - if (visible) - open(); - else if (wasVisible && !visible) - close(); -} - -void WindowBase::center() -{ - // Centre dialog - - // 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; - mMainWidget->setCoord(coord); -} - -WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager) -{ -} - -void WindowModal::open() -{ - MyGUI::InputManager::getInstance ().addWidgetModal (mMainWidget); -} - -void WindowModal::close() -{ - MyGUI::InputManager::getInstance ().removeWidgetModal (mMainWidget); -} diff --git a/apps/openmw/mwgui/window_base.hpp b/apps/openmw/mwgui/window_base.hpp deleted file mode 100644 index afdf4d065b..0000000000 --- a/apps/openmw/mwgui/window_base.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef MWGUI_WINDOW_BASE_H -#define MWGUI_WINDOW_BASE_H - -#include - -namespace MWBase -{ - class WindowManager; -} - -namespace MWGui -{ - class WindowManager; - - class WindowBase: public OEngine::GUI::Layout - { - public: - WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - - // Events - typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; - - virtual void open() {} - virtual void close () {} - virtual void setVisible(bool visible); - void center(); - - /** Event : Dialog finished, OK button clicked.\n - signature : void method()\n - */ - EventHandle_WindowBase eventDone; - - protected: - /// \todo remove - MWBase::WindowManager& mWindowManager; - }; - - - /* - * "Modal" windows cause the rest of the interface to be unaccessible while they are visible - */ - class WindowModal : public WindowBase - { - public: - WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - virtual void open(); - virtual void close(); - }; -} - -#endif diff --git a/apps/openmw/mwgui/window_pinnable_base.cpp b/apps/openmw/mwgui/window_pinnable_base.cpp deleted file mode 100644 index 651b3a1e98..0000000000 --- a/apps/openmw/mwgui/window_pinnable_base.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "window_pinnable_base.hpp" - -#include "../mwbase/windowmanager.hpp" - -#include "exposedwindow.hpp" - -using namespace MWGui; - -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) -{ - ExposedWindow* window = static_cast(mMainWidget); - mPinButton = window->getSkinWidget ("Button"); - - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); -} - -void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) -{ - mPinned = !mPinned; - - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); - - onPinToggled(); -} diff --git a/apps/openmw/mwgui/window_pinnable_base.hpp b/apps/openmw/mwgui/window_pinnable_base.hpp deleted file mode 100644 index 50259858e2..0000000000 --- a/apps/openmw/mwgui/window_pinnable_base.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef MWGUI_WINDOW_PINNABLE_BASE_H -#define MWGUI_WINDOW_PINNABLE_BASE_H - -#include "window_base.hpp" - -namespace MWGui -{ - class WindowManager; - - class WindowPinnableBase: public WindowBase - { - public: - WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); - bool pinned() { return mPinned; } - - private: - void onPinButtonClicked(MyGUI::Widget* _sender); - - protected: - virtual void onPinToggled() = 0; - - MyGUI::Widget* mPinButton; - bool mPinned; - bool mVisible; - }; -} - -#endif From d61ec1063e7c008ea2a1b6a1d90b60d94de85624 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 20:14:10 +0200 Subject: [PATCH 0385/1537] added script editor --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/columnbase.hpp | 3 +- apps/opencs/model/world/columns.hpp | 25 +++++++ apps/opencs/model/world/data.cpp | 1 + apps/opencs/view/world/scriptsubview.cpp | 92 ++++++++++++++++++++++++ apps/opencs/view/world/scriptsubview.hpp | 62 ++++++++++++++++ apps/opencs/view/world/subviews.cpp | 2 + 7 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 apps/opencs/view/world/scriptsubview.cpp create mode 100644 apps/opencs/view/world/scriptsubview.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 76d4280c8f..bd882892fd 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -55,7 +55,7 @@ opencs_hdrs_noqt (view/doc opencs_units (view/world - table tablesubview + table tablesubview scriptsubview ) opencs_units_noqt (view/world diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 23049164f8..fea618037c 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -35,7 +35,8 @@ namespace CSMWorld Display_Specialisation, Display_Attribute, Display_Boolean, - Display_SpellType + Display_SpellType, + Display_Script }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 6d6d1b1ef0..9242e8a23b 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -723,6 +723,31 @@ namespace CSMWorld return true; } }; + + template + struct ScriptColumn : public Column + { + ScriptColumn() : Column ("Script", ColumnBase::Display_Script, 0) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mScriptText.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mScriptText = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 14aff47e89..9f6b186c0c 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -93,6 +93,7 @@ CSMWorld::Data::Data() mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); + mScripts.addColumn (new ScriptColumn); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp new file mode 100644 index 0000000000..2fdb44aec3 --- /dev/null +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -0,0 +1,92 @@ + +#include "scriptsubview.hpp" + +#include + +#include + +#include "../../model/doc/document.hpp" +#include "../../model/world/universalid.hpp" +#include "../../model/world/data.hpp" +#include "../../model/world/columnbase.hpp" +#include "../../model/world/commands.hpp" +#include "../../model/world/idtable.hpp" + +CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) +{ + ++mView.mChangeLocked; +} + +CSVWorld::ScriptSubView::ChangeLock::~ChangeLock() +{ + --mView.mChangeLocked; +} + +CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) +: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) +{ + setWidget (mEditor = new QTextEdit (this)); + + mEditor->setAcceptRichText (false); + mEditor->setLineWrapMode (QTextEdit::NoWrap); + mEditor->setTabStopWidth (4); + mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead + + mModel = &dynamic_cast ( + *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); + + for (int i=0; icolumnCount(); ++i) + if (mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display)== + CSMWorld::ColumnBase::Display_Script) + { + mColumn = i; + break; + } + + if (mColumn==-1) + throw std::logic_error ("Can't find script column"); + + mEditor->setPlainText (mModel->data (mModel->getModelIndex (id.getId(), mColumn)).toString()); + + connect (mEditor, SIGNAL (textChanged()), this, SLOT (textChanged())); + + connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), + this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); + +// connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int start, int end)), +// this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int start, int end))); +} + +void CSVWorld::ScriptSubView::setEditLock (bool locked) +{ + mEditor->setReadOnly (locked); +} + +void CSVWorld::ScriptSubView::textChanged() +{ + ChangeLock lock (*this); + + mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, + mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); +} + +void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) +{ + if (mChangeLocked) + return; + + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + + if (index.row()>=topLeft.row() && index.row()<=bottomRight.row() && + index.column()>=topLeft.column() && index.column()<=bottomRight.column()) + { + QTextCursor cursor = mEditor->textCursor(); + mEditor->setPlainText (mModel->data (index).toString()); + mEditor->setTextCursor (cursor); + } +} + +void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) +{ + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp new file mode 100644 index 0000000000..07d87d9476 --- /dev/null +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -0,0 +1,62 @@ +#ifndef CSV_WORLD_SCRIPTSUBVIEW_H +#define CSV_WORLD_SCRIPTSUBVIEW_H + +#include "../doc/subview.hpp" + +class QTextEdit; +class QModelIndex; + +namespace CSMDoc +{ + class Document; +} + +namespace CSMWorld +{ + class IdTable; +} + +namespace CSVWorld +{ + class ScriptSubView : public CSVDoc::SubView + { + Q_OBJECT + + QTextEdit *mEditor; + CSMDoc::Document& mDocument; + CSMWorld::IdTable *mModel; + int mColumn; + int mChangeLocked; + + class ChangeLock + { + ScriptSubView& mView; + + ChangeLock (const ChangeLock&); + ChangeLock& operator= (const ChangeLock&); + + public: + + ChangeLock (ScriptSubView& view); + ~ChangeLock(); + }; + + friend class ChangeLock; + + public: + + ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document); + + virtual void setEditLock (bool locked); + + private slots: + + void textChanged(); + + void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); + + void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index c9ef4df8db..8f7887f3b9 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -5,6 +5,7 @@ #include "tablesubview.hpp" #include "dialoguesubview.hpp" +#include "scriptsubview.hpp" void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) { @@ -32,6 +33,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) for (int i=0; sTableTypes[i]!=CSMWorld::UniversalId::Type_None; ++i) manager.add (sTableTypes[i], new CSVDoc::SubViewFactoryWithCreateFlag (true)); + manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory); // manager.add (CSMWorld::UniversalId::Type_Global, // new CSVDoc::SubViewFactoryWithCreateFlag (true)); From f7383905b7ca21a6aae6dd438ce0cc948eedf2be Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 10 Apr 2013 14:46:21 -0400 Subject: [PATCH 0386/1537] Finally eliminated calls to MWBase::WindowManager in constructors --- apps/openmw/mwgui/alchemywindow.cpp | 4 +- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/birth.cpp | 4 +- apps/openmw/mwgui/birth.hpp | 2 +- apps/openmw/mwgui/bookwindow.cpp | 4 +- apps/openmw/mwgui/bookwindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.cpp | 197 +++++++++++----------- apps/openmw/mwgui/charactercreation.hpp | 4 +- apps/openmw/mwgui/class.cpp | 44 ++--- apps/openmw/mwgui/class.hpp | 18 +- apps/openmw/mwgui/companionwindow.cpp | 4 +- apps/openmw/mwgui/companionwindow.hpp | 2 +- apps/openmw/mwgui/confirmationdialog.cpp | 4 +- apps/openmw/mwgui/confirmationdialog.hpp | 2 +- apps/openmw/mwgui/container.cpp | 4 +- apps/openmw/mwgui/container.hpp | 2 +- apps/openmw/mwgui/countdialog.cpp | 4 +- apps/openmw/mwgui/countdialog.hpp | 2 +- apps/openmw/mwgui/dialogue.cpp | 10 +- apps/openmw/mwgui/dialogue.hpp | 4 +- apps/openmw/mwgui/enchantingdialog.cpp | 10 +- apps/openmw/mwgui/enchantingdialog.hpp | 2 +- apps/openmw/mwgui/inventorywindow.cpp | 4 +- apps/openmw/mwgui/inventorywindow.hpp | 2 +- apps/openmw/mwgui/itemselection.cpp | 4 +- apps/openmw/mwgui/itemselection.hpp | 2 +- apps/openmw/mwgui/journalwindow.cpp | 4 +- apps/openmw/mwgui/journalwindow.hpp | 2 +- apps/openmw/mwgui/levelupdialog.cpp | 4 +- apps/openmw/mwgui/levelupdialog.hpp | 2 +- apps/openmw/mwgui/loadingscreen.cpp | 4 +- apps/openmw/mwgui/loadingscreen.hpp | 2 +- apps/openmw/mwgui/mapwindow.cpp | 4 +- apps/openmw/mwgui/mapwindow.hpp | 2 +- apps/openmw/mwgui/merchantrepair.cpp | 4 +- apps/openmw/mwgui/merchantrepair.hpp | 2 +- apps/openmw/mwgui/messagebox.cpp | 4 +- apps/openmw/mwgui/messagebox.hpp | 2 +- apps/openmw/mwgui/quickkeysmenu.cpp | 18 +- apps/openmw/mwgui/quickkeysmenu.hpp | 6 +- apps/openmw/mwgui/race.cpp | 4 +- apps/openmw/mwgui/race.hpp | 2 +- apps/openmw/mwgui/repair.cpp | 4 +- apps/openmw/mwgui/repair.hpp | 2 +- apps/openmw/mwgui/review.cpp | 4 +- apps/openmw/mwgui/review.hpp | 2 +- apps/openmw/mwgui/scrollwindow.cpp | 4 +- apps/openmw/mwgui/scrollwindow.hpp | 2 +- apps/openmw/mwgui/settingswindow.cpp | 4 +- apps/openmw/mwgui/settingswindow.hpp | 2 +- apps/openmw/mwgui/spellbuyingwindow.cpp | 4 +- apps/openmw/mwgui/spellbuyingwindow.hpp | 2 +- apps/openmw/mwgui/spellcreationdialog.cpp | 18 +- apps/openmw/mwgui/spellcreationdialog.hpp | 6 +- apps/openmw/mwgui/spellwindow.cpp | 4 +- apps/openmw/mwgui/spellwindow.hpp | 2 +- apps/openmw/mwgui/statswindow.cpp | 4 +- apps/openmw/mwgui/statswindow.hpp | 2 +- apps/openmw/mwgui/textinput.cpp | 4 +- apps/openmw/mwgui/textinput.hpp | 2 +- apps/openmw/mwgui/tooltips.cpp | 2 +- apps/openmw/mwgui/tooltips.hpp | 2 +- apps/openmw/mwgui/tradewindow.cpp | 4 +- apps/openmw/mwgui/tradewindow.hpp | 2 +- apps/openmw/mwgui/trainingwindow.cpp | 4 +- apps/openmw/mwgui/trainingwindow.hpp | 2 +- apps/openmw/mwgui/travelwindow.cpp | 4 +- apps/openmw/mwgui/travelwindow.hpp | 2 +- apps/openmw/mwgui/waitdialog.cpp | 10 +- apps/openmw/mwgui/waitdialog.hpp | 4 +- apps/openmw/mwgui/widgets.cpp | 14 +- apps/openmw/mwgui/widgets.hpp | 4 - apps/openmw/mwgui/windowbase.cpp | 6 +- apps/openmw/mwgui/windowbase.hpp | 4 +- apps/openmw/mwgui/windowmanagerimp.cpp | 58 +++---- apps/openmw/mwgui/windowpinnablebase.cpp | 4 +- apps/openmw/mwgui/windowpinnablebase.hpp | 2 +- 77 files changed, 300 insertions(+), 309 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index 1ae534797d..a6121c234c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -26,8 +26,8 @@ namespace namespace MWGui { - AlchemyWindow::AlchemyWindow(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_alchemy_window.layout", parWindowManager) + AlchemyWindow::AlchemyWindow() + : WindowBase("openmw_alchemy_window.layout") , ContainerBase(0), mApparatus (4), mIngredients (4) { getWidget(mCreateButton, "CreateButton"); diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 933975f0c8..c61d2f92b3 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -14,7 +14,7 @@ namespace MWGui class AlchemyWindow : public WindowBase, public ContainerBase { public: - AlchemyWindow(MWBase::WindowManager& parWindowManager); + AlchemyWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index d899ab00b1..133bbd32fb 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -24,8 +24,8 @@ bool sortBirthSigns(const std::pair& left, c } -BirthDialog::BirthDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_birth.layout", parWindowManager) +BirthDialog::BirthDialog() + : WindowModal("openmw_chargen_birth.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 033501f22f..cc958ddcaa 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -13,7 +13,7 @@ namespace MWGui class BirthDialog : public WindowModal { public: - BirthDialog(MWBase::WindowManager& parWindowManager); + BirthDialog(); enum Gender { diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index d57953d07d..ce74c48593 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -14,8 +14,8 @@ using namespace MWGui; -BookWindow::BookWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_book.layout", parWindowManager) +BookWindow::BookWindow () + : WindowBase("openmw_book.layout") , mTakeButtonShow(true) , mTakeButtonAllowed(true) { diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index c2a9dca893..9123969e09 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -12,7 +12,7 @@ namespace MWGui class BookWindow : public WindowBase { public: - BookWindow(MWBase::WindowManager& parWindowManager); + BookWindow(); void open(MWWorld::Ptr book); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 27de7cee98..0dd6502c6c 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -47,7 +47,7 @@ namespace using namespace MWGui; -CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) +CharacterCreation::CharacterCreation() : mNameDialog(0) , mRaceDialog(0) , mClassChoiceDialog(0) @@ -58,7 +58,6 @@ CharacterCreation::CharacterCreation(MWBase::WindowManager* _wm) , mBirthSignDialog(0) , mReviewDialog(0) , mGenerateClassStep(0) - , mWM(_wm) { mCreationStage = CSE_NotStarted; } @@ -118,10 +117,10 @@ void CharacterCreation::spawnDialog(const char id) switch (id) { case GM_Name: - mWM->removeDialog(mNameDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; - mNameDialog = new TextInputDialog(*mWM); - mNameDialog->setTextLabel(mWM->getGameSettingString("sName", "Name")); + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); mNameDialog->setTextInput(mPlayerName); mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); @@ -129,9 +128,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Race: - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; - mRaceDialog = new RaceDialog(*mWM); + mRaceDialog = new RaceDialog(); mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); mRaceDialog->setRaceId(mPlayerRaceId); mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); @@ -142,9 +141,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Class: - mWM->removeDialog(mClassChoiceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(*mWM); + mClassChoiceDialog = new ClassChoiceDialog(); mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); mClassChoiceDialog->setVisible(true); if (mCreationStage < CSE_RaceChosen) @@ -152,9 +151,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassPick: - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(*mWM); + mPickClassDialog = new PickClassDialog(); mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mPickClassDialog->setClassId(mPlayerClass.mName); mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); @@ -165,9 +164,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_Birth: - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(*mWM); + mBirthSignDialog = new BirthDialog(); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); @@ -178,9 +177,9 @@ void CharacterCreation::spawnDialog(const char id) break; case GM_ClassCreate: - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(*mWM); + mCreateClassDialog = new CreateClassDialog(); mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); @@ -199,9 +198,9 @@ void CharacterCreation::spawnDialog(const char id) mCreationStage = CSE_RaceChosen; break; case GM_Review: - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mReviewDialog = new ReviewDialog(*mWM); + mReviewDialog = new ReviewDialog(); mReviewDialog->setPlayerName(mPlayerName); mReviewDialog->setRace(mPlayerRaceId); mReviewDialog->setClass(mPlayerClass); @@ -212,7 +211,7 @@ void CharacterCreation::spawnDialog(const char id) mReviewDialog->setFatigue(mPlayerFatigue); { - std::map > attributes = mWM->getPlayerAttributeValues(); + std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); for (std::map >::iterator it = attributes.begin(); it != attributes.end(); ++it) { @@ -221,13 +220,13 @@ void CharacterCreation::spawnDialog(const char id) } { - std::map > skills = mWM->getPlayerSkillValues(); + std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); for (std::map >::iterator it = skills.begin(); it != skills.end(); ++it) { mReviewDialog->setSkillValue(static_cast (it->first), it->second); } - mReviewDialog->configureSkills(mWM->getPlayerMajorSkills(), mWM->getPlayerMinorSkills()); + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); } mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); @@ -257,41 +256,41 @@ void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } void CharacterCreation::onReviewDialogBack() { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } void CharacterCreation::onReviewActivateDialog(int parDialog) { - mWM->removeDialog(mReviewDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); mReviewDialog = 0; mCreationStage = CSE_ReviewNext; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(parDialog) { case ReviewDialog::NAME_DIALOG: - mWM->pushGuiMode(GM_Name); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); break; case ReviewDialog::RACE_DIALOG: - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; case ReviewDialog::CLASS_DIALOG: - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); break; case ReviewDialog::BIRTHSIGN_DIALOG: - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; } @@ -308,27 +307,27 @@ void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) if (klass) { mPlayerClass = *klass; - mWM->setPlayerClass(mPlayerClass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); } - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; } //TODO This bit gets repeated a few times; wrap it in a function if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -339,34 +338,34 @@ void CharacterCreation::onPickClassDialogBack() const std::string classId = mPickClassDialog->getClassId(); if (!classId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - mWM->removeDialog(mPickClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassChoice(int _index) { - mWM->removeDialog(mClassChoiceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); mClassChoiceDialog = 0; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); switch(_index) { case ClassChoiceDialog::Class_Generate: - mWM->pushGuiMode(GM_ClassGenerate); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); break; case ClassChoiceDialog::Class_Pick: - mWM->pushGuiMode(GM_ClassPick); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); break; case ClassChoiceDialog::Class_Create: - mWM->pushGuiMode(GM_ClassCreate); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); break; case ClassChoiceDialog::Class_Back: - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); break; }; @@ -377,26 +376,26 @@ void CharacterCreation::onNameDialogDone(WindowBase* parWindow) if (mNameDialog) { mPlayerName = mNameDialog->getTextInput(); - mWM->setValue("name", mPlayerName); + MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); - mWM->removeDialog(mNameDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); mNameDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_NameChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Race); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); } else { mCreationStage = CSE_NameChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -414,12 +413,12 @@ void CharacterCreation::onRaceDialogBack() data.mHair ); } - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Name); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); } void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) @@ -436,26 +435,26 @@ void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) data.mHair ); } - mWM->getInventoryWindow()->rebuildAvatar(); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - mWM->removeDialog(mRaceDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); mRaceDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_RaceChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } else { mCreationStage = CSE_RaceChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -466,19 +465,19 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) mPlayerBirthSignId = mBirthSignDialog->getBirthId(); if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; } if (mCreationStage >= CSE_BirthSignChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else { mCreationStage = CSE_BirthSignChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } @@ -487,12 +486,12 @@ void CharacterCreation::onBirthSignDialogBack() if (mBirthSignDialog) { MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - mWM->removeDialog(mBirthSignDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; } - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) @@ -522,49 +521,49 @@ void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); mPlayerClass = klass; - mWM->setPlayerClass(klass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; } if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } void CharacterCreation::onCreateClassDialogBack() { - mWM->removeDialog(mCreateClassDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onClassQuestionChosen(int _index) { MWBase::Environment::get().getSoundManager()->stopSay(); - mWM->removeDialog(mGenerateClassQuestionDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = 0; if (_index < 0 || _index >= 3) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } @@ -637,10 +636,10 @@ void CharacterCreation::showClassQuestionDialog() } } - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; - mGenerateClassResultDialog = new GenerateClassResultDialog(*mWM); + mGenerateClassResultDialog = new GenerateClassResultDialog(); mGenerateClassResultDialog->setClassId(mGenerateClass); mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); @@ -650,15 +649,15 @@ void CharacterCreation::showClassQuestionDialog() if (mGenerateClassStep > 10) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); return; } - mWM->removeDialog(mGenerateClassQuestionDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); mGenerateClassQuestionDialog = 0; - mGenerateClassQuestionDialog = new InfoBoxDialog(*mWM); + mGenerateClassQuestionDialog = new InfoBoxDialog(); InfoBoxDialog::ButtonList buttons; mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); @@ -674,18 +673,18 @@ void CharacterCreation::showClassQuestionDialog() void CharacterCreation::onGenerateClassBack() { - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Class); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); } void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - mWM->removeDialog(mGenerateClassResultDialog); + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); @@ -694,22 +693,22 @@ void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); mPlayerClass = *klass; - mWM->setPlayerClass(mPlayerClass); + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); if (mCreationStage == CSE_ReviewNext) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Review); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); } else if (mCreationStage >= CSE_ClassChosen) { - mWM->popGuiMode(); - mWM->pushGuiMode(GM_Birth); + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); } else { mCreationStage = CSE_ClassChosen; - mWM->popGuiMode(); + MWBase::Environment::get().getWindowManager()->popGuiMode(); } } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index 9653aeede5..fed77e889f 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -29,7 +29,7 @@ namespace MWGui public: typedef std::vector SkillList; - CharacterCreation(MWBase::WindowManager* _wm); + CharacterCreation(); ~CharacterCreation(); //Show a dialog @@ -58,8 +58,6 @@ namespace MWGui BirthDialog* mBirthSignDialog; ReviewDialog* mReviewDialog; - MWBase::WindowManager* mWM; - //Player data std::string mPlayerName; std::string mPlayerRaceId; diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 8c352d5080..6edad9e83b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -20,8 +20,8 @@ using namespace MWGui; /* GenerateClassResultDialog */ -GenerateClassResultDialog::GenerateClassResultDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_generate_class_result.layout", parWindowManager) +GenerateClassResultDialog::GenerateClassResultDialog() + : WindowModal("openmw_chargen_generate_class_result.layout") { // Centre dialog center(); @@ -67,8 +67,8 @@ void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) /* PickClassDialog */ -PickClassDialog::PickClassDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_class.layout", parWindowManager) +PickClassDialog::PickClassDialog() + : WindowModal("openmw_chargen_class.layout") { // Centre dialog center(); @@ -272,8 +272,8 @@ void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) widget->setSize(width, pos); } -InfoBoxDialog::InfoBoxDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_infobox.layout", parWindowManager) +InfoBoxDialog::InfoBoxDialog() + : WindowModal("openmw_infobox.layout") , mCurrentButton(-1) { getWidget(mTextBox, "TextBox"); @@ -356,8 +356,8 @@ void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) /* ClassChoiceDialog */ -ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) - : InfoBoxDialog(parWindowManager) +ClassChoiceDialog::ClassChoiceDialog() + : InfoBoxDialog() { setText(""); ButtonList buttons; @@ -370,8 +370,8 @@ ClassChoiceDialog::ClassChoiceDialog(MWBase::WindowManager& parWindowManager) /* CreateClassDialog */ -CreateClassDialog::CreateClassDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_create_class.layout", parWindowManager) +CreateClassDialog::CreateClassDialog() + : WindowModal("openmw_chargen_create_class.layout") , mSpecDialog(NULL) , mAttribDialog(NULL) , mSkillDialog(NULL) @@ -540,7 +540,7 @@ void CreateClassDialog::onDialogCancel() void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) { delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(*MWBase::Environment::get().getWindowManager()); + mSpecDialog = new SelectSpecializationDialog(); mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); mSpecDialog->setVisible(true); @@ -571,7 +571,7 @@ void CreateClassDialog::setSpecialization(int id) void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) { delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager()); + mAttribDialog = new SelectAttributeDialog(); mAffectedAttribute = _sender; mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); @@ -601,7 +601,7 @@ void CreateClassDialog::onAttributeSelected() void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) { delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager()); + mSkillDialog = new SelectSkillDialog(); mAffectedSkill = _sender; mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); @@ -633,7 +633,7 @@ void CreateClassDialog::onSkillSelected() void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) { - mDescDialog = new DescriptionDialog(*MWBase::Environment::get().getWindowManager()); + mDescDialog = new DescriptionDialog(); mDescDialog->setTextInput(mDescription); mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); mDescDialog->setVisible(true); @@ -660,8 +660,8 @@ void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) /* SelectSpecializationDialog */ -SelectSpecializationDialog::SelectSpecializationDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_specialization.layout", parWindowManager) +SelectSpecializationDialog::SelectSpecializationDialog() + : WindowModal("openmw_chargen_select_specialization.layout") { // Centre dialog center(); @@ -720,8 +720,8 @@ void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectAttributeDialog */ -SelectAttributeDialog::SelectAttributeDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_attribute.layout", parWindowManager) +SelectAttributeDialog::SelectAttributeDialog() + : WindowModal("openmw_chargen_select_attribute.layout") { // Centre dialog center(); @@ -766,8 +766,8 @@ void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) /* SelectSkillDialog */ -SelectSkillDialog::SelectSkillDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_select_skill.layout", parWindowManager) +SelectSkillDialog::SelectSkillDialog() + : WindowModal("openmw_chargen_select_skill.layout") { // Centre dialog center(); @@ -856,8 +856,8 @@ void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) /* DescriptionDialog */ -DescriptionDialog::DescriptionDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_class_description.layout", parWindowManager) +DescriptionDialog::DescriptionDialog() + : WindowModal("openmw_chargen_class_description.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 11da1a7913..15fc89658f 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -15,7 +15,7 @@ namespace MWGui class InfoBoxDialog : public WindowModal { public: - InfoBoxDialog(MWBase::WindowManager& parWindowManager); + InfoBoxDialog(); typedef std::vector ButtonList; @@ -60,13 +60,13 @@ namespace MWGui Class_Create = 2, Class_Back = 3 }; - ClassChoiceDialog(MWBase::WindowManager& parWindowManager); + ClassChoiceDialog(); }; class GenerateClassResultDialog : public WindowModal { public: - GenerateClassResultDialog(MWBase::WindowManager& parWindowManager); + GenerateClassResultDialog(); std::string getClassId() const; void setClassId(const std::string &classId); @@ -93,7 +93,7 @@ namespace MWGui class PickClassDialog : public WindowModal { public: - PickClassDialog(MWBase::WindowManager& parWindowManager); + PickClassDialog(); const std::string &getClassId() const { return mCurrentClassId; } void setClassId(const std::string &classId); @@ -132,7 +132,7 @@ namespace MWGui class SelectSpecializationDialog : public WindowModal { public: - SelectSpecializationDialog(MWBase::WindowManager& parWindowManager); + SelectSpecializationDialog(); ~SelectSpecializationDialog(); ESM::Class::Specialization getSpecializationId() const { return mSpecializationId; } @@ -163,7 +163,7 @@ namespace MWGui class SelectAttributeDialog : public WindowModal { public: - SelectAttributeDialog(MWBase::WindowManager& parWindowManager); + SelectAttributeDialog(); ~SelectAttributeDialog(); ESM::Attribute::AttributeID getAttributeId() const { return mAttributeId; } @@ -192,7 +192,7 @@ namespace MWGui class SelectSkillDialog : public WindowModal { public: - SelectSkillDialog(MWBase::WindowManager& parWindowManager); + SelectSkillDialog(); ~SelectSkillDialog(); ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } @@ -225,7 +225,7 @@ namespace MWGui class DescriptionDialog : public WindowModal { public: - DescriptionDialog(MWBase::WindowManager& parWindowManager); + DescriptionDialog(); ~DescriptionDialog(); std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } @@ -241,7 +241,7 @@ namespace MWGui class CreateClassDialog : public WindowModal { public: - CreateClassDialog(MWBase::WindowManager& parWindowManager); + CreateClassDialog(); virtual ~CreateClassDialog(); std::string getName() const; diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 643cdf4c65..0a20c471ab 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -13,9 +13,9 @@ namespace MWGui { -CompanionWindow::CompanionWindow(MWBase::WindowManager &parWindowManager, DragAndDrop *dragAndDrop, MessageBoxManager* manager) +CompanionWindow::CompanionWindow(DragAndDrop *dragAndDrop, MessageBoxManager* manager) : ContainerBase(dragAndDrop) - , WindowBase("openmw_companion_window.layout", parWindowManager) + , WindowBase("openmw_companion_window.layout") , mMessageBoxManager(manager) { MyGUI::ScrollView* itemView; diff --git a/apps/openmw/mwgui/companionwindow.hpp b/apps/openmw/mwgui/companionwindow.hpp index 1b64a34d50..073a77a916 100644 --- a/apps/openmw/mwgui/companionwindow.hpp +++ b/apps/openmw/mwgui/companionwindow.hpp @@ -11,7 +11,7 @@ namespace MWGui class CompanionWindow : public ContainerBase, public WindowBase { public: - CompanionWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop, MessageBoxManager* manager); + CompanionWindow(DragAndDrop* dragAndDrop, MessageBoxManager* manager); virtual ~CompanionWindow() {} void open(MWWorld::Ptr npc); diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 31f4989e07..904468f886 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -7,8 +7,8 @@ namespace MWGui { - ConfirmationDialog::ConfirmationDialog(MWBase::WindowManager& parWindowManager) : - WindowModal("openmw_confirmation_dialog.layout", parWindowManager) + ConfirmationDialog::ConfirmationDialog() : + WindowModal("openmw_confirmation_dialog.layout") { getWidget(mMessage, "Message"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/confirmationdialog.hpp b/apps/openmw/mwgui/confirmationdialog.hpp index a925cad550..47b256017f 100644 --- a/apps/openmw/mwgui/confirmationdialog.hpp +++ b/apps/openmw/mwgui/confirmationdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class ConfirmationDialog : public WindowModal { public: - ConfirmationDialog(MWBase::WindowManager& parWindowManager); + ConfirmationDialog(); void open(const std::string& message); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index f7846e70ec..8ee4754a32 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -649,9 +649,9 @@ MWWorld::ContainerStore& ContainerBase::getContainerStore() // ------------------------------------------------------------------------------------------------ -ContainerWindow::ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) +ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window.layout", parWindowManager) + , WindowBase("openmw_container_window.layout") { getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); getWidget(mTakeButton, "TakeButton"); diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 7a3e804e5d..521ac8cc35 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -134,7 +134,7 @@ namespace MWGui class ContainerWindow : public ContainerBase, public WindowBase { public: - ContainerWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + ContainerWindow(DragAndDrop* dragAndDrop); virtual ~ContainerWindow(); diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 61c3c358a2..d017cc1986 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -7,8 +7,8 @@ namespace MWGui { - CountDialog::CountDialog(MWBase::WindowManager& parWindowManager) : - WindowModal("openmw_count_window.layout", parWindowManager) + CountDialog::CountDialog() : + WindowModal("openmw_count_window.layout") { getWidget(mSlider, "CountSlider"); getWidget(mItemEdit, "ItemEdit"); diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp index d5155839d8..9d6d8b263f 100644 --- a/apps/openmw/mwgui/countdialog.hpp +++ b/apps/openmw/mwgui/countdialog.hpp @@ -8,7 +8,7 @@ namespace MWGui class CountDialog : public WindowModal { public: - CountDialog(MWBase::WindowManager& parWindowManager); + CountDialog(); 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/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 0939da1b17..f3c11752e8 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -55,8 +55,8 @@ bool sortByLength (const std::string& left, const std::string& right) -PersuasionDialog::PersuasionDialog(MWBase::WindowManager &parWindowManager) - : WindowModal("openmw_persuasion_dialog.layout", parWindowManager) +PersuasionDialog::PersuasionDialog() + : WindowModal("openmw_persuasion_dialog.layout") { getWidget(mCancelButton, "CancelButton"); getWidget(mAdmireButton, "AdmireButton"); @@ -124,9 +124,9 @@ void PersuasionDialog::open() // -------------------------------------------------------------------------------------------------- -DialogueWindow::DialogueWindow(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_dialogue_window.layout", parWindowManager) - , mPersuasionDialog(parWindowManager) +DialogueWindow::DialogueWindow() + : WindowBase("openmw_dialogue_window.layout") + , mPersuasionDialog() , mEnabled(false) , mServices(0) { diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index e78856c951..a1bbee02c7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -29,7 +29,7 @@ namespace MWGui class PersuasionDialog : public WindowModal { public: - PersuasionDialog(MWBase::WindowManager& parWindowManager); + PersuasionDialog(); virtual void open(); @@ -50,7 +50,7 @@ namespace MWGui class DialogueWindow: public WindowBase, public ReferenceInterface { public: - DialogueWindow(MWBase::WindowManager& parWindowManager); + DialogueWindow(); // Events typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; diff --git a/apps/openmw/mwgui/enchantingdialog.cpp b/apps/openmw/mwgui/enchantingdialog.cpp index 02d847d1a8..2ae98f358f 100644 --- a/apps/openmw/mwgui/enchantingdialog.cpp +++ b/apps/openmw/mwgui/enchantingdialog.cpp @@ -15,9 +15,9 @@ namespace MWGui { - EnchantingDialog::EnchantingDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_enchanting_dialog.layout", parWindowManager) - , EffectEditorBase(parWindowManager) + EnchantingDialog::EnchantingDialog() + : WindowBase("openmw_enchanting_dialog.layout") + , EffectEditorBase() , mItemSelectionDialog(NULL) { getWidget(mName, "NameEdit"); @@ -139,7 +139,7 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sEnchantItems}", - ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic, *MWBase::Environment::get().getWindowManager()); + ContainerBase::Filter_Apparel|ContainerBase::Filter_Weapon|ContainerBase::Filter_NoMagic); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onItemSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onItemCancel); mItemSelectionDialog->setVisible(true); @@ -227,7 +227,7 @@ namespace MWGui { delete mItemSelectionDialog; mItemSelectionDialog = new ItemSelectionDialog("#{sSoulGemsWithSouls}", - ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones, *MWBase::Environment::get().getWindowManager()); + ContainerBase::Filter_Misc|ContainerBase::Filter_ChargedSoulstones); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &EnchantingDialog::onSoulSelected); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &EnchantingDialog::onSoulCancel); mItemSelectionDialog->setVisible(true); diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index 822199ac67..c727a09749 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -17,7 +17,7 @@ namespace MWGui class EnchantingDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: - EnchantingDialog(MWBase::WindowManager& parWindowManager); + EnchantingDialog(); virtual ~EnchantingDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 393f03a541..dc7ef77ff8 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -30,9 +30,9 @@ namespace MWGui { - InventoryWindow::InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + InventoryWindow::InventoryWindow(DragAndDrop* dragAndDrop) : ContainerBase(dragAndDrop) - , WindowPinnableBase("openmw_inventory_window.layout", parWindowManager) + , WindowPinnableBase("openmw_inventory_window.layout") , mTrading(false) , mLastXSize(0) , mLastYSize(0) diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp index 61ee17ef93..a4ed89d401 100644 --- a/apps/openmw/mwgui/inventorywindow.hpp +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -12,7 +12,7 @@ namespace MWGui class InventoryWindow : public ContainerBase, public WindowPinnableBase { public: - InventoryWindow(MWBase::WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + InventoryWindow(DragAndDrop* dragAndDrop); virtual void open(); diff --git a/apps/openmw/mwgui/itemselection.cpp b/apps/openmw/mwgui/itemselection.cpp index 4b8adcef4f..ed8b47b086 100644 --- a/apps/openmw/mwgui/itemselection.cpp +++ b/apps/openmw/mwgui/itemselection.cpp @@ -3,9 +3,9 @@ namespace MWGui { - ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter, MWBase::WindowManager& parWindowManager) + ItemSelectionDialog::ItemSelectionDialog(const std::string &label, int filter) : ContainerBase(NULL) - , WindowModal("openmw_itemselection_dialog.layout", parWindowManager) + , WindowModal("openmw_itemselection_dialog.layout") { mFilter = filter; diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 733daa91ae..3e812d26c5 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -8,7 +8,7 @@ namespace MWGui class ItemSelectionDialog : public ContainerBase, public WindowModal { public: - ItemSelectionDialog(const std::string& label, int filter, MWBase::WindowManager& parWindowManager); + ItemSelectionDialog(const std::string& label, int filter); typedef MyGUI::delegates::CMultiDelegate0 EventHandle_Void; typedef MyGUI::delegates::CMultiDelegate1 EventHandle_Item; diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index ba39b01012..a3198d6bcd 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -81,8 +81,8 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) } -MWGui::JournalWindow::JournalWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_journal.layout", parWindowManager) +MWGui::JournalWindow::JournalWindow () + : WindowBase("openmw_journal.layout") , mPageNumber(0) { mMainWidget->setVisible(false); diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 73a2dca2ec..7670b65f55 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -14,7 +14,7 @@ namespace MWGui class JournalWindow : public WindowBase { public: - JournalWindow(MWBase::WindowManager& parWindowManager); + JournalWindow(); virtual void open(); virtual void close(); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index dcecdccc1b..fc1317e908 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -18,8 +18,8 @@ namespace MWGui { - LevelupDialog::LevelupDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_levelup_dialog.layout", parWindowManager) + LevelupDialog::LevelupDialog() + : WindowBase("openmw_levelup_dialog.layout") { getWidget(mOkButton, "OkButton"); getWidget(mClassImage, "ClassImage"); diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp index a54948e2a0..69afbf0897 100644 --- a/apps/openmw/mwgui/levelupdialog.hpp +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui class LevelupDialog : public WindowBase { public: - LevelupDialog(MWBase::WindowManager& parWindowManager); + LevelupDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 3066705124..858c3f36ec 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -23,10 +23,10 @@ namespace MWGui { - LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager) + LoadingScreen::LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw) : mSceneMgr(sceneMgr) , mWindow(rw) - , WindowBase("openmw_loading_screen.layout", parWindowManager) + , WindowBase("openmw_loading_screen.layout") , mLoadingOn(false) , mLastRenderTime(0.f) , mLastWallpaperChangeTime(0.f) diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index cb33975ae3..12e6504bca 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -11,7 +11,7 @@ namespace MWGui class LoadingScreen : public WindowBase { public: - LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw, MWBase::WindowManager& parWindowManager); + LoadingScreen(Ogre::SceneManager* sceneMgr, Ogre::RenderWindow* rw); virtual ~LoadingScreen(); void setLoadingProgress (const std::string& stage, int depth, int current, int total); diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 029974d2b3..17834be937 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -262,8 +262,8 @@ void LocalMapBase::setPlayerDir(const float x, const float y) // ------------------------------------------------------------------------------------------ -MapWindow::MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout", parWindowManager) +MapWindow::MapWindow(const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout") , mGlobal(false) { setCoord(500,0,320,300); diff --git a/apps/openmw/mwgui/mapwindow.hpp b/apps/openmw/mwgui/mapwindow.hpp index 329854e182..18c81a0608 100644 --- a/apps/openmw/mwgui/mapwindow.hpp +++ b/apps/openmw/mwgui/mapwindow.hpp @@ -65,7 +65,7 @@ namespace MWGui class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase { public: - MapWindow(MWBase::WindowManager& parWindowManager, const std::string& cacheDir); + MapWindow(const std::string& cacheDir); virtual ~MapWindow(); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index f24d2d4177..53148cb3f0 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -19,8 +19,8 @@ namespace MWGui { -MerchantRepair::MerchantRepair(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_merchantrepair.layout", parWindowManager) +MerchantRepair::MerchantRepair() + : WindowBase("openmw_merchantrepair.layout") { getWidget(mList, "RepairView"); getWidget(mOkButton, "OkButton"); diff --git a/apps/openmw/mwgui/merchantrepair.hpp b/apps/openmw/mwgui/merchantrepair.hpp index 2cd6c486a9..4cb39fe012 100644 --- a/apps/openmw/mwgui/merchantrepair.hpp +++ b/apps/openmw/mwgui/merchantrepair.hpp @@ -12,7 +12,7 @@ namespace MWGui class MerchantRepair : public WindowBase { public: - MerchantRepair(MWBase::WindowManager &parWindowManager); + MerchantRepair(); virtual void open(); diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 58bbc3c3ab..8e53380bde 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -7,7 +7,7 @@ using namespace MWGui; -MessageBoxManager::MessageBoxManager (MWBase::WindowManager* windowManager) +MessageBoxManager::MessageBoxManager () { // defines mMessageBoxSpeed = 0.1; @@ -212,7 +212,7 @@ int MessageBox::getHeight () InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout", *MWBase::Environment::get().getWindowManager()) + : WindowModal("openmw_interactive_messagebox.layout") , mMessageBoxManager(parMessageBoxManager) , mButtonPressed(-1) { diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index c64953b665..cb40739023 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -31,7 +31,7 @@ namespace MWGui class MessageBoxManager { public: - MessageBoxManager (MWBase::WindowManager* windowManager); + MessageBoxManager (); void onFrame (float frameDuration); void createMessageBox (const std::string& message); bool createInteractiveMessageBox (const std::string& message, const std::vector& buttons); diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 82835a8058..2deb37d301 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -43,8 +43,8 @@ namespace namespace MWGui { - QuickKeysMenu::QuickKeysMenu(MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_quickkeys_menu.layout", parWindowManager) + QuickKeysMenu::QuickKeysMenu() + : WindowBase("openmw_quickkeys_menu.layout") , mAssignDialog(0) , mItemSelectionDialog(0) , mMagicSelectionDialog(0) @@ -109,7 +109,7 @@ namespace MWGui { // open assign dialog if (!mAssignDialog) - mAssignDialog = new QuickKeysMenuAssign(*MWBase::Environment::get().getWindowManager(), this); + mAssignDialog = new QuickKeysMenuAssign(this); mAssignDialog->setVisible (true); } } @@ -124,7 +124,7 @@ namespace MWGui { if (!mItemSelectionDialog ) { - mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All, *MWBase::Environment::get().getWindowManager()); + mItemSelectionDialog = new ItemSelectionDialog("#{sQuickMenu6}", ContainerBase::Filter_All); mItemSelectionDialog->eventItemSelected += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItem); mItemSelectionDialog->eventDialogCanceled += MyGUI::newDelegate(this, &QuickKeysMenu::onAssignItemCancel); } @@ -139,7 +139,7 @@ namespace MWGui { if (!mMagicSelectionDialog ) { - mMagicSelectionDialog = new MagicSelectionDialog(*MWBase::Environment::get().getWindowManager(), this); + mMagicSelectionDialog = new MagicSelectionDialog(this); } mMagicSelectionDialog->setVisible(true); @@ -352,8 +352,8 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - QuickKeysMenuAssign::QuickKeysMenuAssign (MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) - : WindowModal("openmw_quickkeys_menu_assign.layout", parWindowManager) + QuickKeysMenuAssign::QuickKeysMenuAssign (QuickKeysMenu* parent) + : WindowModal("openmw_quickkeys_menu_assign.layout") , mParent(parent) { getWidget(mLabel, "Label"); @@ -399,8 +399,8 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - MagicSelectionDialog::MagicSelectionDialog(MWBase::WindowManager &parWindowManager, QuickKeysMenu* parent) - : WindowModal("openmw_magicselection_dialog.layout", parWindowManager) + MagicSelectionDialog::MagicSelectionDialog(QuickKeysMenu* parent) + : WindowModal("openmw_magicselection_dialog.layout") , mParent(parent) , mWidth(0) , mHeight(0) diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index d5b6e6cd85..646ec2aa45 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -16,7 +16,7 @@ namespace MWGui class QuickKeysMenu : public WindowBase { public: - QuickKeysMenu(MWBase::WindowManager& parWindowManager); + QuickKeysMenu(); ~QuickKeysMenu(); @@ -64,7 +64,7 @@ namespace MWGui class QuickKeysMenuAssign : public WindowModal { public: - QuickKeysMenuAssign(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + QuickKeysMenuAssign(QuickKeysMenu* parent); private: MyGUI::TextBox* mLabel; @@ -79,7 +79,7 @@ namespace MWGui class MagicSelectionDialog : public WindowModal { public: - MagicSelectionDialog(MWBase::WindowManager& parWindowManager, QuickKeysMenu* parent); + MagicSelectionDialog(QuickKeysMenu* parent); virtual void open(); diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 167ad573a0..9a0d8a029f 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -62,8 +62,8 @@ int countParts(const std::string &part, const std::string &race, bool male) } } -RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_race.layout", parWindowManager) +RaceDialog::RaceDialog() + : WindowModal("openmw_chargen_race.layout") , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 4a4acd0112..f3adce4447 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -26,7 +26,7 @@ namespace MWGui class RaceDialog : public WindowModal { public: - RaceDialog(MWBase::WindowManager& parWindowManager); + RaceDialog(); enum Gender { diff --git a/apps/openmw/mwgui/repair.cpp b/apps/openmw/mwgui/repair.cpp index 43c262ad85..0bd4b0995f 100644 --- a/apps/openmw/mwgui/repair.cpp +++ b/apps/openmw/mwgui/repair.cpp @@ -15,8 +15,8 @@ namespace MWGui { -Repair::Repair(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_repair.layout", parWindowManager) +Repair::Repair() + : WindowBase("openmw_repair.layout") { getWidget(mRepairBox, "RepairBox"); getWidget(mRepairView, "RepairView"); diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 824e0b6d2a..5d9a487199 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -12,7 +12,7 @@ namespace MWGui class Repair : public WindowBase { public: - Repair(MWBase::WindowManager &parWindowManager); + Repair(); virtual void open(); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 74b1893456..562bf97748 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -22,8 +22,8 @@ using namespace Widgets; const int ReviewDialog::sLineHeight = 18; -ReviewDialog::ReviewDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_chargen_review.layout", parWindowManager) +ReviewDialog::ReviewDialog() + : WindowModal("openmw_chargen_review.layout") , mLastPos(0) { // Centre dialog diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 9775a52de4..d5df94e285 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -28,7 +28,7 @@ namespace MWGui }; typedef std::vector SkillList; - ReviewDialog(MWBase::WindowManager& parWindowManager); + ReviewDialog(); void setPlayerName(const std::string &name); void setRace(const std::string &raceId); diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 22884bfe6d..1935f7a9b6 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -12,8 +12,8 @@ using namespace MWGui; -ScrollWindow::ScrollWindow (MWBase::WindowManager& parWindowManager) - : WindowBase("openmw_scroll.layout", parWindowManager) +ScrollWindow::ScrollWindow () + : WindowBase("openmw_scroll.layout") , mTakeButtonShow(true) , mTakeButtonAllowed(true) { diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 59b39cab38..5feaff7bf8 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -11,7 +11,7 @@ namespace MWGui class ScrollWindow : public WindowBase { public: - ScrollWindow (MWBase::WindowManager& parWindowManager); + ScrollWindow (); void open (MWWorld::Ptr scroll); void setTakeButtonShow(bool show); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index e21d4f5894..c3718c2607 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -93,8 +93,8 @@ namespace namespace MWGui { - SettingsWindow::SettingsWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_settings_window.layout", parWindowManager) + SettingsWindow::SettingsWindow() : + WindowBase("openmw_settings_window.layout") { getWidget(mOkButton, "OkButton"); getWidget(mSubtitlesButton, "SubtitlesButton"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index 292c1233de..6dcef2422e 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -13,7 +13,7 @@ namespace MWGui class SettingsWindow : public WindowBase { public: - SettingsWindow(MWBase::WindowManager& parWindowManager); + SettingsWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 9aa8074a24..7d634df8d6 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -23,8 +23,8 @@ namespace MWGui { const int SpellBuyingWindow::sLineHeight = 18; - SpellBuyingWindow::SpellBuyingWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_spell_buying_window.layout", parWindowManager) + SpellBuyingWindow::SpellBuyingWindow() : + WindowBase("openmw_spell_buying_window.layout") , mCurrentY(0) , mLastPos(0) { diff --git a/apps/openmw/mwgui/spellbuyingwindow.hpp b/apps/openmw/mwgui/spellbuyingwindow.hpp index 1418a9db52..f7ea54c89c 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.hpp +++ b/apps/openmw/mwgui/spellbuyingwindow.hpp @@ -21,7 +21,7 @@ namespace MWGui class SpellBuyingWindow : public ReferenceInterface, public WindowBase { public: - SpellBuyingWindow(MWBase::WindowManager& parWindowManager); + SpellBuyingWindow(); void startSpellBuying(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index 6fef91457f..e1df9f9cd1 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -40,8 +40,8 @@ namespace namespace MWGui { - EditEffectDialog::EditEffectDialog(MWBase::WindowManager &parWindowManager) - : WindowModal("openmw_edit_effect.layout", parWindowManager) + EditEffectDialog::EditEffectDialog() + : WindowModal("openmw_edit_effect.layout") , mEditing(false) { getWidget(mCancelButton, "CancelButton"); @@ -274,9 +274,9 @@ namespace MWGui // ------------------------------------------------------------------------------------------------ - SpellCreationDialog::SpellCreationDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_spellcreation_dialog.layout", parWindowManager) - , EffectEditorBase(parWindowManager) + SpellCreationDialog::SpellCreationDialog() + : WindowBase("openmw_spellcreation_dialog.layout") + , EffectEditorBase() { getWidget(mNameEdit, "NameEdit"); getWidget(mMagickaCost, "MagickaCost"); @@ -412,8 +412,8 @@ namespace MWGui // ------------------------------------------------------------------------------------------------ - EffectEditorBase::EffectEditorBase(MWBase::WindowManager& parWindowManager) - : mAddEffectDialog(parWindowManager) + EffectEditorBase::EffectEditorBase() + : mAddEffectDialog() , mSelectAttributeDialog(NULL) , mSelectSkillDialog(NULL) { @@ -541,7 +541,7 @@ namespace MWGui if (effect->mData.mFlags & ESM::MagicEffect::TargetSkill) { delete mSelectSkillDialog; - mSelectSkillDialog = new SelectSkillDialog(*MWBase::Environment::get().getWindowManager ()); + mSelectSkillDialog = new SelectSkillDialog(); mSelectSkillDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel); mSelectSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectSkill); mSelectSkillDialog->setVisible (true); @@ -549,7 +549,7 @@ namespace MWGui else if (effect->mData.mFlags & ESM::MagicEffect::TargetAttribute) { delete mSelectAttributeDialog; - mSelectAttributeDialog = new SelectAttributeDialog(*MWBase::Environment::get().getWindowManager ()); + mSelectAttributeDialog = new SelectAttributeDialog(); mSelectAttributeDialog->eventCancel += MyGUI::newDelegate(this, &SpellCreationDialog::onAttributeOrSkillCancel); mSelectAttributeDialog->eventItemSelected += MyGUI::newDelegate(this, &SpellCreationDialog::onSelectAttribute); mSelectAttributeDialog->setVisible (true); diff --git a/apps/openmw/mwgui/spellcreationdialog.hpp b/apps/openmw/mwgui/spellcreationdialog.hpp index facbdf5304..5ad306fbea 100644 --- a/apps/openmw/mwgui/spellcreationdialog.hpp +++ b/apps/openmw/mwgui/spellcreationdialog.hpp @@ -15,7 +15,7 @@ namespace MWGui class EditEffectDialog : public WindowModal { public: - EditEffectDialog(MWBase::WindowManager& parWindowManager); + EditEffectDialog(); virtual void open(); @@ -83,7 +83,7 @@ namespace MWGui class EffectEditorBase { public: - EffectEditorBase(MWBase::WindowManager& parWindowManager); + EffectEditorBase(); protected: @@ -123,7 +123,7 @@ namespace MWGui class SpellCreationDialog : public WindowBase, public ReferenceInterface, public EffectEditorBase { public: - SpellCreationDialog(MWBase::WindowManager& parWindowManager); + SpellCreationDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index 257fab89d4..d07f9ca542 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -47,8 +47,8 @@ namespace namespace MWGui { - SpellWindow::SpellWindow(MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_spell_window.layout", parWindowManager) + SpellWindow::SpellWindow() + : WindowPinnableBase("openmw_spell_window.layout") , mHeight(0) , mWidth(0) { diff --git a/apps/openmw/mwgui/spellwindow.hpp b/apps/openmw/mwgui/spellwindow.hpp index b0994c5901..521e73d767 100644 --- a/apps/openmw/mwgui/spellwindow.hpp +++ b/apps/openmw/mwgui/spellwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class SpellWindow : public WindowPinnableBase { public: - SpellWindow(MWBase::WindowManager& parWindowManager); + SpellWindow(); virtual ~SpellWindow(); void updateSpells(); diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 0e0676c2fb..a00ec167da 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -22,8 +22,8 @@ using namespace MWGui; const int StatsWindow::sLineHeight = 18; -StatsWindow::StatsWindow (MWBase::WindowManager& parWindowManager) - : WindowPinnableBase("openmw_stats_window.layout", parWindowManager) +StatsWindow::StatsWindow () + : WindowPinnableBase("openmw_stats_window.layout") , mSkillView(NULL) , mClientHeight(0) , mMajorSkills() diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 93e26e063d..4b723048cc 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -22,7 +22,7 @@ namespace MWGui typedef std::vector SkillList; - StatsWindow(MWBase::WindowManager& parWindowManager); + StatsWindow(); /// automatically updates all the data in the stats window, but only if it has changed. void onFrame(); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index 071971befb..ab2936cfce 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -5,8 +5,8 @@ using namespace MWGui; -TextInputDialog::TextInputDialog(MWBase::WindowManager& parWindowManager) - : WindowModal("openmw_text_input.layout", parWindowManager) +TextInputDialog::TextInputDialog() + : WindowModal("openmw_text_input.layout") { // Centre dialog center(); diff --git a/apps/openmw/mwgui/textinput.hpp b/apps/openmw/mwgui/textinput.hpp index 6b371bae74..1f53263ecd 100644 --- a/apps/openmw/mwgui/textinput.hpp +++ b/apps/openmw/mwgui/textinput.hpp @@ -13,7 +13,7 @@ namespace MWGui class TextInputDialog : public WindowModal { public: - TextInputDialog(MWBase::WindowManager& parWindowManager); + TextInputDialog(); std::string getTextInput() const { return mTextEdit ? mTextEdit->getOnlyText() : ""; } void setTextInput(const std::string &text) { if (mTextEdit) mTextEdit->setOnlyText(text); } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 7730019e83..2250ffd0b5 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -19,7 +19,7 @@ using namespace MWGui; using namespace MyGUI; -ToolTips::ToolTips(MWBase::WindowManager* windowManager) : +ToolTips::ToolTips() : Layout("openmw_tooltips.layout") , mGameMode(true) , mFullHelp(false) diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index e4fcb310c8..f8f256167b 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -39,7 +39,7 @@ namespace MWGui class ToolTips : public OEngine::GUI::Layout { public: - ToolTips(MWBase::WindowManager* windowManager); + ToolTips(); void onFrame(float frameDuration); diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index 718e6378bb..718f40c785 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -24,8 +24,8 @@ namespace MWGui const float TradeWindow::sBalanceChangeInitialPause = 0.5; const float TradeWindow::sBalanceChangeInterval = 0.1; - TradeWindow::TradeWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_trade_window.layout", parWindowManager) + TradeWindow::TradeWindow() : + WindowBase("openmw_trade_window.layout") , ContainerBase(NULL) // no drag&drop , mCurrentBalance(0) , mBalanceButtonsState(BBS_None) diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index 111c0935fe..e526a42ca5 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TradeWindow : public ContainerBase, public WindowBase { public: - TradeWindow(MWBase::WindowManager& parWindowManager); + TradeWindow(); void startTrade(MWWorld::Ptr actor); diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index c2b543a4fd..f85a8be594 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -20,8 +20,8 @@ namespace MWGui { - TrainingWindow::TrainingWindow(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_trainingwindow.layout", parWindowManager) + TrainingWindow::TrainingWindow() + : WindowBase("openmw_trainingwindow.layout") , mFadeTimeRemaining(0) { getWidget(mTrainingOptions, "TrainingOptions"); diff --git a/apps/openmw/mwgui/trainingwindow.hpp b/apps/openmw/mwgui/trainingwindow.hpp index d6be60ae67..740115cdfc 100644 --- a/apps/openmw/mwgui/trainingwindow.hpp +++ b/apps/openmw/mwgui/trainingwindow.hpp @@ -10,7 +10,7 @@ namespace MWGui class TrainingWindow : public WindowBase, public ReferenceInterface { public: - TrainingWindow(MWBase::WindowManager& parWindowManager); + TrainingWindow(); virtual void open(); diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index b710171669..0a74c921af 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -25,8 +25,8 @@ namespace MWGui { const int TravelWindow::sLineHeight = 18; - TravelWindow::TravelWindow(MWBase::WindowManager& parWindowManager) : - WindowBase("openmw_travel_window.layout", parWindowManager) + TravelWindow::TravelWindow() : + WindowBase("openmw_travel_window.layout") , mCurrentY(0) , mLastPos(0) { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index 61b724910c..a814d04785 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -23,7 +23,7 @@ namespace MWGui class TravelWindow : public ReferenceInterface, public WindowBase { public: - TravelWindow(MWBase::WindowManager& parWindowManager); + TravelWindow(); void startTravel(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 69dfa10b4d..a84b9203a9 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -25,8 +25,8 @@ namespace MWGui { - WaitDialogProgressBar::WaitDialogProgressBar(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_wait_dialog_progressbar.layout", parWindowManager) + WaitDialogProgressBar::WaitDialogProgressBar() + : WindowBase("openmw_wait_dialog_progressbar.layout") { getWidget(mProgressBar, "ProgressBar"); getWidget(mProgressText, "ProgressText"); @@ -46,9 +46,9 @@ namespace MWGui // --------------------------------------------------------------------------------------------------------- - WaitDialog::WaitDialog(MWBase::WindowManager &parWindowManager) - : WindowBase("openmw_wait_dialog.layout", parWindowManager) - , mProgressBar(parWindowManager) + WaitDialog::WaitDialog() + : WindowBase("openmw_wait_dialog.layout") + , mProgressBar() , mWaiting(false) , mSleeping(false) , mHours(1) diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp index 4510e665b3..d06d7d1128 100644 --- a/apps/openmw/mwgui/waitdialog.hpp +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -9,7 +9,7 @@ namespace MWGui class WaitDialogProgressBar : public WindowBase { public: - WaitDialogProgressBar(MWBase::WindowManager& parWindowManager); + WaitDialogProgressBar(); virtual void open(); @@ -23,7 +23,7 @@ namespace MWGui class WaitDialog : public WindowBase { public: - WaitDialog(MWBase::WindowManager& parWindowManager); + WaitDialog(); virtual void open(); diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 3801ae6f7a..dd3206ed65 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -34,8 +34,7 @@ void MWGui::Widgets::fixTexturePath(std::string &path) /* MWSkill */ MWSkill::MWSkill() - : mManager(NULL) - , mSkillId(ESM::Skill::Length) + : mSkillId(ESM::Skill::Length) , mSkillNameWidget(NULL) , mSkillValueWidget(NULL) { @@ -65,7 +64,7 @@ void MWSkill::setSkillValue(const SkillValue& value) void MWSkill::updateWidgets() { - if (mSkillNameWidget && mManager) + if (mSkillNameWidget) { if (mSkillId == ESM::Skill::Length) { @@ -73,7 +72,7 @@ void MWSkill::updateWidgets() } else { - const std::string &name = mManager->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); static_cast(mSkillNameWidget)->setCaption(name); } } @@ -126,8 +125,7 @@ void MWSkill::initialiseOverride() /* MWAttribute */ MWAttribute::MWAttribute() - : mManager(NULL) - , mId(-1) + : mId(-1) , mAttributeNameWidget(NULL) , mAttributeValueWidget(NULL) { @@ -152,7 +150,7 @@ void MWAttribute::onClicked(MyGUI::Widget* _sender) void MWAttribute::updateWidgets() { - if (mAttributeNameWidget && mManager) + if (mAttributeNameWidget) { if (mId < 0 || mId >= 8) { @@ -170,7 +168,7 @@ void MWAttribute::updateWidgets() "sAttributePersonality", "sAttributeLuck" }; - const std::string &name = mManager->getGameSettingString(attributes[mId], ""); + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); static_cast(mAttributeNameWidget)->setCaption(name); } } diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 26ca750667..038ce3f86f 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -98,7 +98,6 @@ namespace MWGui void setSkillNumber(int skillId); void setSkillValue(const SkillValue& value); - MWBase::WindowManager *getWindowManager() const { return mManager; } ESM::Skill::SkillEnum getSkillId() const { return mSkillId; } const SkillValue& getSkillValue() const { return mValue; } @@ -121,7 +120,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager *mManager; ESM::Skill::SkillEnum mSkillId; SkillValue mValue; MyGUI::Widget* mSkillNameWidget; @@ -140,7 +138,6 @@ namespace MWGui void setAttributeId(int attributeId); void setAttributeValue(const AttributeValue& value); - MWBase::WindowManager *getWindowManager() const { return mManager; } int getAttributeId() const { return mId; } const AttributeValue& getAttributeValue() const { return mValue; } @@ -163,7 +160,6 @@ namespace MWGui void updateWidgets(); - MWBase::WindowManager *mManager; int mId; AttributeValue mValue; MyGUI::Widget* mAttributeNameWidget; diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index cb3d4ea8c8..c41bcb7ce6 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -6,7 +6,7 @@ using namespace MWGui; -WindowBase::WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) +WindowBase::WindowBase(const std::string& parLayout) : Layout(parLayout) { } @@ -38,8 +38,8 @@ void WindowBase::center() mMainWidget->setCoord(coord); } -WindowModal::WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager) +WindowModal::WindowModal(const std::string& parLayout) + : WindowBase(parLayout) { } diff --git a/apps/openmw/mwgui/windowbase.hpp b/apps/openmw/mwgui/windowbase.hpp index a2cb731fee..2c014baf0b 100644 --- a/apps/openmw/mwgui/windowbase.hpp +++ b/apps/openmw/mwgui/windowbase.hpp @@ -15,7 +15,7 @@ namespace MWGui class WindowBase: public OEngine::GUI::Layout { public: - WindowBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowBase(const std::string& parLayout); // Events typedef MyGUI::delegates::CMultiDelegate1 EventHandle_WindowBase; @@ -38,7 +38,7 @@ namespace MWGui class WindowModal : public WindowBase { public: - WindowModal(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowModal(const std::string& parLayout); virtual void open(); virtual void close(); }; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bcde82e966..f2ded8813e 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -162,38 +162,38 @@ WindowManager::WindowManager( mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mMenu = new MainMenu(w,h); - mMap = new MapWindow(*this, cacheDir); - mStatsWindow = new StatsWindow(*this); + mMap = new MapWindow(cacheDir); + mStatsWindow = new StatsWindow(); mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(*this); - mMessageBoxManager = new MessageBoxManager(this); - mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); - mTradeWindow = new TradeWindow(*this); - mSpellBuyingWindow = new SpellBuyingWindow(*this); - mTravelWindow = new TravelWindow(*this); - mDialogueWindow = new DialogueWindow(*this); - mContainerWindow = new ContainerWindow(*this,mDragAndDrop); + mJournal = new JournalWindow(); + mMessageBoxManager = new MessageBoxManager(); + mInventoryWindow = new InventoryWindow(mDragAndDrop); + mTradeWindow = new TradeWindow(); + mSpellBuyingWindow = new SpellBuyingWindow(); + mTravelWindow = new TravelWindow(); + mDialogueWindow = new DialogueWindow(); + mContainerWindow = new ContainerWindow(mDragAndDrop); mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); - mToolTips = new ToolTips(this); - mScrollWindow = new ScrollWindow(*this); - mBookWindow = new BookWindow(*this); - mCountDialog = new CountDialog(*this); - mSettingsWindow = new SettingsWindow(*this); - mConfirmationDialog = new ConfirmationDialog(*this); - mAlchemyWindow = new AlchemyWindow(*this); - mSpellWindow = new SpellWindow(*this); - mQuickKeysMenu = new QuickKeysMenu(*this); - mLevelupDialog = new LevelupDialog(*this); - mWaitDialog = new WaitDialog(*this); - mSpellCreationDialog = new SpellCreationDialog(*this); - mEnchantingDialog = new EnchantingDialog(*this); - mTrainingWindow = new TrainingWindow(*this); - mMerchantRepair = new MerchantRepair(*this); - mRepair = new Repair(*this); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mBookWindow = new BookWindow(); + mCountDialog = new CountDialog(); + mSettingsWindow = new SettingsWindow(); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); + mSpellWindow = new SpellWindow(); + mQuickKeysMenu = new QuickKeysMenu(); + mLevelupDialog = new LevelupDialog(); + mWaitDialog = new WaitDialog(); + mSpellCreationDialog = new SpellCreationDialog(); + mEnchantingDialog = new EnchantingDialog(); + mTrainingWindow = new TrainingWindow(); + mMerchantRepair = new MerchantRepair(); + mRepair = new Repair(); mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(*this, mDragAndDrop, mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow (), *this); + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); mLoadingScreen->onResChange (w,h); mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); @@ -202,7 +202,7 @@ WindowManager::WindowManager( mHud->setVisible(mHudEnabled); - mCharGen = new CharacterCreation(this); + mCharGen = new CharacterCreation(); // Setup player stats for (int i = 0; i < ESM::Attribute::Length; ++i) diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 54ed082cf9..56868306ac 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -6,8 +6,8 @@ using namespace MWGui; -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager) - : WindowBase(parLayout, parWindowManager), mPinned(false), mVisible(false) +WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) + : WindowBase(parLayout), mPinned(false), mVisible(false) { ExposedWindow* window = static_cast(mMainWidget); mPinButton = window->getSkinWidget ("Button"); diff --git a/apps/openmw/mwgui/windowpinnablebase.hpp b/apps/openmw/mwgui/windowpinnablebase.hpp index 657e8142f1..1ab6294328 100644 --- a/apps/openmw/mwgui/windowpinnablebase.hpp +++ b/apps/openmw/mwgui/windowpinnablebase.hpp @@ -10,7 +10,7 @@ namespace MWGui class WindowPinnableBase: public WindowBase { public: - WindowPinnableBase(const std::string& parLayout, MWBase::WindowManager& parWindowManager); + WindowPinnableBase(const std::string& parLayout); bool pinned() { return mPinned; } private: From 3a87b12bafefd6b7f97c9a2ddac43fddc496d549 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 21:31:14 +0200 Subject: [PATCH 0387/1537] delete script subview on script deletion --- apps/opencs/view/world/scriptsubview.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 2fdb44aec3..0319033b00 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -53,8 +53,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); -// connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int start, int end)), -// this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int start, int end))); + connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), + this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); } void CSVWorld::ScriptSubView::setEditLock (bool locked) @@ -88,5 +88,8 @@ void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QMo void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end) { + QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); + if (!parent.isValid() && index.row()>=start && index.row()<=end) + deleteLater(); } \ No newline at end of file From 6c6750342c321b537fcc7cc14246050fc4bf2580 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 13:37:20 -0700 Subject: [PATCH 0388/1537] Specified particle size is actually the radius --- components/nif/data.hpp | 4 ++-- components/nifogre/ogrenifloader.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/components/nif/data.hpp b/components/nif/data.hpp index bd109041f1..f1f34184ba 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -167,7 +167,7 @@ class NiAutoNormalParticlesData : public ShapeData public: int numParticles; - float particleSize; + float particleRadius; int activeCount; @@ -180,7 +180,7 @@ public: // Should always match the number of vertices numParticles = nif->getUShort(); - particleSize = nif->getFloat(); + particleRadius = nif->getFloat(); activeCount = nif->getUShort(); if(nif->getInt()) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3c876283e1..62732d387d 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -1543,7 +1543,8 @@ class NIFObjectLoader : Ogre::ManualResourceLoader vertprop, zprop, specprop, wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleSize, particledata->particleSize); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); From 74145410f24d6c60b6cdca81aa14e40564691cda Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Wed, 10 Apr 2013 22:49:22 +0200 Subject: [PATCH 0389/1537] basic syntax highlighting in script subview --- apps/opencs/CMakeLists.txt | 4 +- apps/opencs/model/world/scriptcontext.cpp | 22 ++++ apps/opencs/model/world/scriptcontext.hpp | 26 +++++ apps/opencs/view/world/scripthighlighter.cpp | 105 +++++++++++++++++++ apps/opencs/view/world/scripthighlighter.hpp | 77 ++++++++++++++ apps/opencs/view/world/scriptsubview.cpp | 4 + components/CMakeLists.txt | 2 +- components/compiler/nullerrorhandler.cpp | 6 ++ components/compiler/nullerrorhandler.hpp | 21 ++++ 9 files changed, 264 insertions(+), 3 deletions(-) create mode 100644 apps/opencs/model/world/scriptcontext.cpp create mode 100644 apps/opencs/model/world/scriptcontext.hpp create mode 100644 apps/opencs/view/world/scripthighlighter.cpp create mode 100644 apps/opencs/view/world/scripthighlighter.hpp create mode 100644 components/compiler/nullerrorhandler.cpp create mode 100644 components/compiler/nullerrorhandler.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index bd882892fd..5c15938bda 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase + universalid data record idcollection commands columnbase scriptcontext ) opencs_hdrs_noqt (model/world @@ -59,7 +59,7 @@ opencs_units (view/world ) opencs_units_noqt (view/world - dialoguesubview util subviews enumdelegate vartypedelegate + dialoguesubview util subviews enumdelegate vartypedelegate scripthighlighter ) diff --git a/apps/opencs/model/world/scriptcontext.cpp b/apps/opencs/model/world/scriptcontext.cpp new file mode 100644 index 0000000000..69b72abf26 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.cpp @@ -0,0 +1,22 @@ + +#include "scriptcontext.hpp" + +bool CSMWorld::ScriptContext::canDeclareLocals() const +{ + return false; +} + +char CSMWorld::ScriptContext::getGlobalType (const std::string& name) const +{ + return ' '; +} + +char CSMWorld::ScriptContext::getMemberType (const std::string& name, const std::string& id) const +{ + return ' '; +} + +bool CSMWorld::ScriptContext::isId (const std::string& name) const +{ + return false; +} \ No newline at end of file diff --git a/apps/opencs/model/world/scriptcontext.hpp b/apps/opencs/model/world/scriptcontext.hpp new file mode 100644 index 0000000000..1231aea649 --- /dev/null +++ b/apps/opencs/model/world/scriptcontext.hpp @@ -0,0 +1,26 @@ +#ifndef CSM_WORLD_SCRIPTCONTEXT_H +#define CSM_WORLD_SCRIPTCONTEXT_H + +#include + +namespace CSMWorld +{ + class ScriptContext : public Compiler::Context + { + public: + + virtual bool canDeclareLocals() const; + ///< Is the compiler allowed to declare local variables? + + virtual char getGlobalType (const std::string& name) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual char getMemberType (const std::string& name, const std::string& id) const; + ///< 'l: long, 's': short, 'f': float, ' ': does not exist. + + virtual bool isId (const std::string& name) const; + ///< Does \a name match an ID, that can be referenced? + }; +} + +#endif diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp new file mode 100644 index 0000000000..1e93ac26b7 --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -0,0 +1,105 @@ + +#include "scripthighlighter.hpp" + +#include + +#include + +bool CSVWorld::ScriptHighlighter::parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Int); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Float); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Name); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Keyword); + return true; +} + +bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner) +{ + highlight (loc, Type_Special); + return true; +} + +void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) +{} + +void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type type) +{ + int length = static_cast (loc.mLiteral.size()); + + int index = loc.mColumn; + + // compensate for bug in Compiler::Scanner (position of token is the character after the token) + index -= length; + + setFormat (index, length, mScheme[type]); +} + +CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) +: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext) +{ + /// \ŧodo replace this with user settings + { + QTextCharFormat format; + format.setForeground (Qt::darkMagenta); + mScheme.insert (std::make_pair (Type_Int, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Float, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::gray); + mScheme.insert (std::make_pair (Type_Name, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::red); + mScheme.insert (std::make_pair (Type_Keyword, format)); + } + + { + QTextCharFormat format; + format.setForeground (Qt::darkYellow); + mScheme.insert (std::make_pair (Type_Special, format)); + } +} + +void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) +{ + std::istringstream stream (text.toUtf8().constData()); + + Compiler::Scanner scanner (mErrorHandler, stream, mContext.getExtensions()); + + try + { + scanner.scan (*this); + } + catch (...) {} // ignore syntax errors + +} \ No newline at end of file diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp new file mode 100644 index 0000000000..e9918f99b7 --- /dev/null +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -0,0 +1,77 @@ +#ifndef CSV_WORLD_SCRIPTHIGHLIGHTER_H +#define CSV_WORLD_SCRIPTHIGHLIGHTER_H + +#include + +#include + +#include +#include + +#include "../../model/world/scriptcontext.hpp" + +namespace CSVWorld +{ + class ScriptHighlighter : public QSyntaxHighlighter, private Compiler::Parser + { + public: + + enum Type + { + Type_Int, + Type_Float, + Type_Name, + Type_Keyword, + Type_Special + }; + + private: + + Compiler::NullErrorHandler mErrorHandler; + CSMWorld::ScriptContext mContext; + std::map mScheme; + + private: + + virtual bool parseInt (int value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle an int token. + /// \return fetch another token? + + virtual bool parseFloat (float value, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a float token. + /// \return fetch another token? + + virtual bool parseName (const std::string& name, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner); + ///< Handle a name token. + /// \return fetch another token? + + virtual bool parseKeyword (int keyword, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a keyword token. + /// \return fetch another token? + + virtual bool parseSpecial (int code, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle a special character token. + /// \return fetch another token? + + ///< Handle a special character token. + /// \return fetch another token? + + virtual void parseEOF (Compiler::Scanner& scanner); + ///< Handle EOF token. + + void highlight (const Compiler::TokenLoc& loc, Type type); + + public: + + ScriptHighlighter (QTextDocument *parent); + + virtual void highlightBlock (const QString& text); + }; +} + +#endif diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index 0319033b00..ab1c2d57c6 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -12,6 +12,8 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" +#include "scripthighlighter.hpp" + CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view) { ++mView.mChangeLocked; @@ -55,6 +57,8 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc: connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); + + new ScriptHighlighter (mEditor->document()); } void CSVWorld::ScriptSubView::setEditLock (bool locked) diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcca..ed12ff2f0e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -54,7 +54,7 @@ add_component_dir (files add_component_dir (compiler context controlparser errorhandler exception exprparser extensions fileparser generator lineparser literals locals output parser scanner scriptparser skipparser streamerrorhandler - stringparser tokenloc + stringparser tokenloc nullerrorhandler ) add_component_dir (interpreter diff --git a/components/compiler/nullerrorhandler.cpp b/components/compiler/nullerrorhandler.cpp new file mode 100644 index 0000000000..3071701e8a --- /dev/null +++ b/components/compiler/nullerrorhandler.cpp @@ -0,0 +1,6 @@ + +#include "nullerrorhandler.hpp" + +void Compiler::NullErrorHandler::report (const std::string& message, const TokenLoc& loc, Type type) {} + +void Compiler::NullErrorHandler::report (const std::string& message, Type type) {} \ No newline at end of file diff --git a/components/compiler/nullerrorhandler.hpp b/components/compiler/nullerrorhandler.hpp new file mode 100644 index 0000000000..bb4db99a28 --- /dev/null +++ b/components/compiler/nullerrorhandler.hpp @@ -0,0 +1,21 @@ + +#ifndef COMPILER_NULLERRORHANDLER_H_INCLUDED +#define COMPILER_NULLERRORHANDLER_H_INCLUDED + +#include "errorhandler.hpp" + +namespace Compiler +{ + /// \brief Error handler implementation: Ignore all error messages + + class NullErrorHandler : public ErrorHandler + { + virtual void report (const std::string& message, const TokenLoc& loc, Type type); + ///< Report error to the user. + + virtual void report (const std::string& message, Type type); + ///< Report a file related error + }; +} + +#endif From 106ef4c9369e303aaf79654c597961e1516f3522 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 10 Apr 2013 22:53:03 +0200 Subject: [PATCH 0390/1537] Rotate script --- apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7e9827062b..7810c2874b 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -318,5 +318,7 @@ op 0x20001fb: DropSoulGem, explicit reference op 0x20001fc: OnDeath op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference +op 0x20001ff: Rotate +op 0x2000200: Rotate, explicit reference -opcodes 0x20001ff-0x3ffffff unused +opcodes 0x2000201-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 49688efb5d..6c4fb0f4bd 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -542,6 +542,42 @@ namespace MWScript } }; + template + class OpRotate : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + runtime.pop(); + + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + + //Axis in morrowind are inverted + if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -568,6 +604,8 @@ namespace MWScript const int opcodePlaceAtMeExplicit = 0x200019e; const int opcodeModScale = 0x20001e3; const int opcodeModScaleExplicit = 0x20001e4; + const int opcodeRotate = 0x20001ff; + const int opcodeRotateExplicit = 0x2000200; void registerExtensions (Compiler::Extensions& extensions) { @@ -585,6 +623,7 @@ namespace MWScript extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); + extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -614,6 +653,8 @@ namespace MWScript interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); interpreter.installSegment5(opcodeModScale,new OpModScale); interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); + interpreter.installSegment5(opcodeRotate,new OpRotate); + interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); } } } From caff28e20acb914997143e51ac503835f3a8fb4d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 19:58:17 -0700 Subject: [PATCH 0391/1537] Move NIFSkeletonLoader to a separate file --- apps/openmw/mwrender/animation.hpp | 3 + components/CMakeLists.txt | 2 +- components/nifogre/ogrenifloader.cpp | 366 +-------------------------- components/nifogre/ogrenifloader.hpp | 4 +- components/nifogre/skeleton.cpp | 351 +++++++++++++++++++++++++ components/nifogre/skeleton.hpp | 63 +++++ 6 files changed, 421 insertions(+), 368 deletions(-) create mode 100644 components/nifogre/skeleton.cpp create mode 100644 components/nifogre/skeleton.hpp diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cfef28f16c..029c56523d 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -1,6 +1,9 @@ #ifndef _GAME_RENDER_ANIMATION_H #define _GAME_RENDER_ANIMATION_H +#include +#include + #include #include "../mwworld/ptr.hpp" diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a2f416fcca..d43725ee08 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader + ogrenifloader skeleton ) add_component_dir (nifbullet diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 62732d387d..0a30f38bd1 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -51,7 +51,7 @@ #include #include -typedef unsigned char ubyte; +#include "skeleton.hpp" namespace std { @@ -424,370 +424,6 @@ public: }; -/** Manual resource loader for NIF skeletons. This is the main class - responsible for translating the internal NIF skeleton structure into - something Ogre can use (includes animations and node TextKeyData). - */ -class NIFSkeletonLoader : public Ogre::ManualResourceLoader -{ -static void warn(const std::string &msg) -{ - std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; -} - -static void fail(const std::string &msg) -{ - std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; - abort(); -} - - -static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) -{ - Ogre::Animation *anim = skel->createAnimation(name, stopTime); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - bool didlast = false; - while(!didlast) - { - float curtime = std::numeric_limits::max(); - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); -} - - -static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL) -{ - Ogre::Bone *bone; - if(!skel->hasBone(node->name)) - bone = skel->createBone(node->name); - else - bone = skel->createBone(); - if(parent) parent->addChild(bone); - mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); - - bone->setOrientation(node->trafo.rotation); - bone->setPosition(node->trafo.pos); - bone->setScale(Ogre::Vector3(node->trafo.scale)); - bone->setBindingPose(); - - if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ - node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ - node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ - node->recType == Nif::RC_NiCamera || - node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles - )) - warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController - )) - warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); - ctrl = ctrl->next; - } - - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - - const Nif::NiNode *ninode = dynamic_cast(node); - if(ninode) - { - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); - } - } -} - -// Lookup to retrieve an Ogre bone handle for a given Nif record index -std::map mNifToOgreHandleMap; - -typedef std::map LoaderMap; -static LoaderMap sLoaders; - -public: -void loadResource(Ogre::Resource *resource) -{ - Ogre::Skeleton *skel = dynamic_cast(resource); - OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); - - Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); - const Nif::Node *node = static_cast(nif->getRoot(0)); - - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; - try { - buildBones(skel, node, animroot, textkeys, ctrls); - } - catch(std::exception &e) { - std::cerr<< "Exception while loading "<getName() < targets; - // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file - if(ctrls.size() == 0) // No animations? Then we're done. - return; - - float maxtime = 0.0f; - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *ctrl = ctrls[i]; - maxtime = std::max(maxtime, ctrl->timeStop); - Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(target != NULL) - targets.push_back(target->name); - } - - if(targets.size() != ctrls.size()) - { - warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ - Ogre::StringConverter::toString(ctrls.size())+" controllers)"); - return; - } - - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - - std::string currentgroup; - TextKeyMap::const_iterator keyiter = textkeys.begin(); - for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) - { - std::string::size_type sep = keyiter->second.find(':'); - if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || - (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) - continue; - currentgroup = keyiter->second.substr(0, sep); - - if(skel->hasAnimation(currentgroup)) - continue; - - TextKeyMap::const_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); - else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first, insiter->second)); - } while(insiter++ != lastkeyiter); - - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); - } -} - - -static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) -{ - /* We need to be a little aggressive here, since some NIFs have a crap-ton - * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers on non- - * NiTriShape nodes, there are no nodes named "AttachLight", and the tree - * consists of NiNode, NiTriShape, and RootCollisionNode types only. - */ - if(!node->boneTrafo) - { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); - if(node->controller.empty() && node->name != "AttachLight") - { - if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) - { - const Nif::NiNode *ninode = static_cast(node); - const Nif::NodeList &children = ninode->children; - for(size_t i = 0;i < children.length();i++) - { - if(!children[i].empty()) - { - Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); - if(!skel.isNull()) - return skel; - } - } - return Ogre::SkeletonPtr(); - } - } - } - - Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); - return skelMgr.create(name, group, true, &sLoaders[name]); -} - -// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be -// used when the bone name is insufficient as this is a relatively slow lookup -static int lookupOgreBoneHandle(const std::string &nifname, int idx) -{ - LoaderMap::const_iterator loader = sLoaders.find(nifname); - if(loader != sLoaders.end()) - { - std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); - if(entry != loader->second.mNifToOgreHandleMap.end()) - return entry->second; - } - throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); -} - -}; -NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; - - // Conversion of blend / test mode from NIF static const char *getBlendFactor(int mode) { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 18bbf0200f..fa5182aeaa 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -25,11 +25,11 @@ #define OPENMW_COMPONENTS_NIFOGRE_OGRENIFLOADER_HPP #include -#include -#include +#include #include #include +#include // FIXME: This namespace really doesn't do anything Nif-specific. Any supportable diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp new file mode 100644 index 0000000000..e97e91ef03 --- /dev/null +++ b/components/nifogre/skeleton.cpp @@ -0,0 +1,351 @@ +#include "skeleton.hpp" + +#include +#include +#include +#include + +#include +#include + +namespace NifOgre +{ + +void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) +{ + Ogre::Animation *anim = skel->createAnimation(name, stopTime); + + for(size_t i = 0;i < ctrls.size();i++) + { + const Nif::NiKeyframeController *kfc = ctrls[i]; + if(kfc->data.empty()) + continue; + const Nif::NiKeyframeData *kf = kfc->data.getPtr(); + + /* Get the keyframes and make sure they're sorted first to last */ + const Nif::QuaternionKeyList &quatkeys = kf->mRotations; + const Nif::Vector3KeyList &trankeys = kf->mTranslations; + const Nif::FloatKeyList &scalekeys = kf->mScales; + + Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); + Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); + Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); + + Ogre::Bone *bone = skel->getBone(targets[i]); + // NOTE: For some reason, Ogre doesn't like the node track ID being different from + // the bone ID + Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? + anim->getNodeTrack(bone->getHandle()) : + anim->createNodeTrack(bone->getHandle(), bone); + + Ogre::Quaternion lastquat, curquat; + Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); + Ogre::Vector3 lastscale(1.0f), curscale(1.0f); + if(quatiter != quatkeys.mKeys.end()) + lastquat = curquat = quatiter->mValue; + if(traniter != trankeys.mKeys.end()) + lasttrans = curtrans = traniter->mValue; + if(scaleiter != scalekeys.mKeys.end()) + lastscale = curscale = Ogre::Vector3(scaleiter->mValue); + + bool didlast = false; + while(!didlast) + { + float curtime = std::numeric_limits::max(); + + //Get latest time + if(quatiter != quatkeys.mKeys.end()) + curtime = std::min(curtime, quatiter->mTime); + if(traniter != trankeys.mKeys.end()) + curtime = std::min(curtime, traniter->mTime); + if(scaleiter != scalekeys.mKeys.end()) + curtime = std::min(curtime, scaleiter->mTime); + + curtime = std::max(curtime, startTime); + if(curtime >= stopTime) + { + didlast = true; + curtime = stopTime; + } + + // Get the latest quaternions, translations, and scales for the + // current time + while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) + { + lastquat = curquat; + if(++quatiter != quatkeys.mKeys.end()) + curquat = quatiter->mValue; + } + while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) + { + lasttrans = curtrans; + if(++traniter != trankeys.mKeys.end()) + curtrans = traniter->mValue; + } + while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) + { + lastscale = curscale; + if(++scaleiter != scalekeys.mKeys.end()) + curscale = Ogre::Vector3(scaleiter->mValue); + } + + Ogre::TransformKeyFrame *kframe; + kframe = nodetrack->createNodeKeyFrame(curtime); + if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) + kframe->setRotation(curquat); + else + { + Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; + float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); + kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); + } + if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) + kframe->setTranslate(curtrans); + else + { + Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; + float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); + kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); + } + if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) + kframe->setScale(curscale); + else + { + Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; + float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); + kframe->setScale(lastscale + ((curscale-lastscale)*diff)); + } + } + } + anim->optimise(); +} + + +TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) +{ + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; +} + +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +{ + Ogre::Bone *bone; + if(!skel->hasBone(node->name)) + bone = skel->createBone(node->name); + else + bone = skel->createBone(); + if(parent) parent->addChild(bone); + mNifToOgreHandleMap[node->recIndex] = bone->getHandle(); + + bone->setOrientation(node->trafo.rotation); + bone->setPosition(node->trafo.pos); + bone->setScale(Ogre::Vector3(node->trafo.scale)); + bone->setBindingPose(); + + if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ + node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ + node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiCamera || + node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles + )) + warn("Unhandled "+node->recName+" "+node->name+" in "+skel->getName()); + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiKeyframeController) + ctrls.push_back(static_cast(ctrl.getPtr())); + else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController + )) + warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); + ctrl = ctrl->next; + } + + Nif::ExtraPtr e = node->extra; + while(!e.empty()) + { + if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + textkeys = extractTextKeys(tk); + animroot = bone; + } + e = e->extra; + } + + const Nif::NiNode *ninode = dynamic_cast(node); + if(ninode) + { + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + } + } +} + +void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) +{ + Ogre::Skeleton *skel = dynamic_cast(resource); + OgreAssert(skel, "Attempting to load a skeleton into a non-skeleton resource!"); + + Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); + const Nif::Node *node = static_cast(nif->getRoot(0)); + + std::vector ctrls; + Ogre::Bone *animroot = NULL; + TextKeyMap textkeys; + try { + buildBones(skel, node, animroot, textkeys, ctrls); + } + catch(std::exception &e) { + std::cerr<< "Exception while loading "<getName() < targets; + // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file + if(ctrls.size() == 0) // No animations? Then we're done. + return; + + float maxtime = 0.0f; + for(size_t i = 0;i < ctrls.size();i++) + { + const Nif::NiKeyframeController *ctrl = ctrls[i]; + maxtime = std::max(maxtime, ctrl->timeStop); + Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); + if(target != NULL) + targets.push_back(target->name); + } + + if(targets.size() != ctrls.size()) + { + warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ + Ogre::StringConverter::toString(ctrls.size())+" controllers)"); + return; + } + + Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); + bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); + + std::string currentgroup; + TextKeyMap::const_iterator keyiter = textkeys.begin(); + for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) + { + std::string::size_type sep = keyiter->second.find(':'); + if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || + (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) + continue; + currentgroup = keyiter->second.substr(0, sep); + + if(skel->hasAnimation(currentgroup)) + continue; + + TextKeyMap::const_iterator lastkeyiter = textkeys.end(); + while((--lastkeyiter)->first > keyiter->first) + { + if(lastkeyiter->second.find(':') == currentgroup.length() && + lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) + break; + } + + buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); + + TextKeyMap::const_iterator insiter(keyiter); + TextKeyMap groupkeys; + do { + sep = insiter->second.find(':'); + if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) + groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); + else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || + (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) + groupkeys.insert(std::make_pair(insiter->first, insiter->second)); + } while(insiter++ != lastkeyiter); + + bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); + } +} + + +Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node) +{ + /* We need to be a little aggressive here, since some NIFs have a crap-ton + * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: + * There are no bones used for skinning, there are no controllers on non- + * NiTriShape nodes, there are no nodes named "AttachLight", and the tree + * consists of NiNode, NiTriShape, and RootCollisionNode types only. + */ + if(!node->boneTrafo) + { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); + if(node->controller.empty() && node->name != "AttachLight") + { + if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) + { + const Nif::NiNode *ninode = static_cast(node); + const Nif::NodeList &children = ninode->children; + for(size_t i = 0;i < children.length();i++) + { + if(!children[i].empty()) + { + Ogre::SkeletonPtr skel = createSkeleton(name, group, children[i].getPtr()); + if(!skel.isNull()) + return skel; + } + } + return Ogre::SkeletonPtr(); + } + } + } + + Ogre::SkeletonManager &skelMgr = Ogre::SkeletonManager::getSingleton(); + return skelMgr.create(name, group, true, &sLoaders[name]); +} + +// Looks up an Ogre Bone handle ID from a NIF's record index. Should only be +// used when the bone name is insufficient as this is a relatively slow lookup +int NIFSkeletonLoader::lookupOgreBoneHandle(const std::string &nifname, int idx) +{ + LoaderMap::const_iterator loader = sLoaders.find(nifname); + if(loader != sLoaders.end()) + { + std::map::const_iterator entry = loader->second.mNifToOgreHandleMap.find(idx); + if(entry != loader->second.mNifToOgreHandleMap.end()) + return entry->second; + } + throw std::runtime_error("Invalid NIF record lookup ("+nifname+", index "+Ogre::StringConverter::toString(idx)+")"); +} + +NIFSkeletonLoader::LoaderMap NIFSkeletonLoader::sLoaders; + +} diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp new file mode 100644 index 0000000000..c69c2a12fe --- /dev/null +++ b/components/nifogre/skeleton.hpp @@ -0,0 +1,63 @@ +#ifndef COMPONENTS_NIFOGRE_SKELETON_HPP +#define COMPONENTS_NIFOGRE_SKELETON_HPP + +#include +#include +#include + +#include + +#include "ogrenifloader.hpp" + +namespace Nif +{ + class NiTextKeyExtraData; + class Node; + class NiKeyframeController; +} + +namespace NifOgre +{ + +/** Manual resource loader for NIF skeletons. This is the main class + responsible for translating the internal NIF skeleton structure into + something Ogre can use (includes animations and node TextKeyData). + */ +class NIFSkeletonLoader : public Ogre::ManualResourceLoader +{ + static void warn(const std::string &msg) + { + std::cerr << "NIFSkeletonLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFSkeletonLoader: Fail: "<< msg << std::endl; + abort(); + } + + static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); + + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + + // Lookup to retrieve an Ogre bone handle for a given Nif record index + std::map mNifToOgreHandleMap; + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + +public: + void loadResource(Ogre::Resource *resource); + + static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); + + // Looks up an Ogre Bone handle ID from a NIF's record index. Should only + // be used when the bone name is insufficient as this is a relatively slow + // lookup + static int lookupOgreBoneHandle(const std::string &nifname, int idx); +}; + +} + +#endif From 39704077722ec64120d6764b8a7e0480cac051be Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 20:22:13 -0700 Subject: [PATCH 0392/1537] Use actual classes for properties --- components/nif/property.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/components/nif/property.hpp b/components/nif/property.hpp index fd96ad0481..06c8260ce5 100644 --- a/components/nif/property.hpp +++ b/components/nif/property.hpp @@ -156,11 +156,11 @@ public: }; // These contain no other data than the 'flags' field in Property -typedef Property NiShadeProperty; -typedef Property NiDitherProperty; -typedef Property NiZBufferProperty; -typedef Property NiSpecularProperty; -typedef Property NiWireframeProperty; +class NiShadeProperty : public Property { }; +class NiDitherProperty : public Property { }; +class NiZBufferProperty : public Property { }; +class NiSpecularProperty : public Property { }; +class NiWireframeProperty : public Property { }; // The rest are all struct-based template @@ -324,10 +324,10 @@ struct S_StencilProperty } }; -typedef StructPropT NiAlphaProperty; -typedef StructPropT NiMaterialProperty; -typedef StructPropT NiVertexColorProperty; -typedef StructPropT NiStencilProperty; +class NiAlphaProperty : public StructPropT { }; +class NiMaterialProperty : public StructPropT { }; +class NiVertexColorProperty : public StructPropT { }; +class NiStencilProperty : public StructPropT { }; } // Namespace #endif From 75489b1e9d583da765dc3da4aedea0f9e8e7fa9b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 20:24:44 -0700 Subject: [PATCH 0393/1537] Move NIFMaterialLoader to a separate file --- components/CMakeLists.txt | 2 +- components/nifogre/material.cpp | 399 ++++++++++++++++++++++++++ components/nifogre/material.hpp | 57 ++++ components/nifogre/ogrenifloader.cpp | 407 +-------------------------- 4 files changed, 458 insertions(+), 407 deletions(-) create mode 100644 components/nifogre/material.cpp create mode 100644 components/nifogre/material.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index d43725ee08..aa422b49e7 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader skeleton + ogrenifloader skeleton material ) add_component_dir (nifbullet diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp new file mode 100644 index 0000000000..431b8219a9 --- /dev/null +++ b/components/nifogre/material.cpp @@ -0,0 +1,399 @@ +#include "material.hpp" + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + + +namespace NifOgre +{ + +// Conversion of blend / test mode from NIF +static const char *getBlendFactor(int mode) +{ + switch(mode) + { + case 0: return "one"; + case 1: return "zero"; + case 2: return "src_colour"; + case 3: return "one_minus_src_colour"; + case 4: return "dest_colour"; + case 5: return "one_minus_dest_colour"; + case 6: return "src_alpha"; + case 7: return "one_minus_src_alpha"; + case 8: return "dest_alpha"; + case 9: return "one_minus_dest_alpha"; + case 10: return "src_alpha_saturate"; + } + std::cerr<< "Unexpected blend mode: "<colors.size() != 0); + + // Texture + if(texprop) + { + for(int i = 0;i < 7;i++) + { + if(!texprop->textures[i].inUse) + continue; + if(texprop->textures[i].texture.empty()) + { + warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); + continue; + } + + const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); + if(st->external) + texName[i] = findTextureName(st->filename); + else + warn("Found internal texture, ignoring."); + } + + Nif::ControllerPtr ctrls = texprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled texture controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); + + // Alpha modifiers + if(alphaprop) + { + alphaFlags = alphaprop->flags; + alphaTest = alphaprop->data.threshold; + + Nif::ControllerPtr ctrls = alphaprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled alpha controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + // Vertex color handling + if(vertprop) + { + vertMode = vertprop->data.vertmode; + // FIXME: Handle lightmode? + //lightMode = vertprop->data.lightmode; + + Nif::ControllerPtr ctrls = vertprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(zprop) + { + depthFlags = zprop->flags; + // Depth function??? + + Nif::ControllerPtr ctrls = zprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled depth controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(specprop) + { + specFlags = specprop->flags; + + Nif::ControllerPtr ctrls = specprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled specular controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + if(wireprop) + { + wireFlags = wireprop->flags; + + Nif::ControllerPtr ctrls = wireprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + // Material + if(matprop) + { + ambient = matprop->data.ambient; + diffuse = matprop->data.diffuse; + specular = matprop->data.specular; + emissive = matprop->data.emissive; + glossiness = matprop->data.glossiness; + alpha = matprop->data.alpha; + + Nif::ControllerPtr ctrls = matprop->controller; + while(!ctrls.empty()) + { + warn("Unhandled material controller "+ctrls->recName+" in "+name); + ctrls = ctrls->next; + } + } + + { + // Generate a hash out of all properties that can affect the material. + size_t h = 0; + boost::hash_combine(h, ambient.x); + boost::hash_combine(h, ambient.y); + boost::hash_combine(h, ambient.z); + boost::hash_combine(h, diffuse.x); + boost::hash_combine(h, diffuse.y); + boost::hash_combine(h, diffuse.z); + boost::hash_combine(h, alpha); + boost::hash_combine(h, specular.x); + boost::hash_combine(h, specular.y); + boost::hash_combine(h, specular.z); + boost::hash_combine(h, glossiness); + boost::hash_combine(h, emissive.x); + boost::hash_combine(h, emissive.y); + boost::hash_combine(h, emissive.z); + for(int i = 0;i < 7;i++) + { + if(!texName[i].empty()) + boost::hash_combine(h, texName[i]); + } + boost::hash_combine(h, vertexColour); + boost::hash_combine(h, alphaFlags); + boost::hash_combine(h, alphaTest); + boost::hash_combine(h, vertMode); + boost::hash_combine(h, depthFlags); + boost::hash_combine(h, specFlags); + boost::hash_combine(h, wireFlags); + + std::map::iterator itr = sMaterialMap.find(h); + if (itr != sMaterialMap.end()) + { + // a suitable material exists already - use it + return itr->second; + } + // not found, create a new one + sMaterialMap.insert(std::make_pair(h, name)); + } + + // No existing material like this. Create a new one. + sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); + if(vertMode == 0 || !vertexColour) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); + } + else if(vertMode == 1) + { + instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); + instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); + instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); + } + else if(vertMode == 2) + { + instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); + instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); + instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); + } + else + std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( + new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); + } + + if(wireFlags) + { + instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); + } + + instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); + instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); + instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); + if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) + { + instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) + { + instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); + instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); + } + if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) + { + // force automips on normal maps for now + instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); + } + + for(int i = 0;i < 7;i++) + { + if(i == Nif::NiTexturingProperty::BaseTexture || + i == Nif::NiTexturingProperty::DetailTexture || + i == Nif::NiTexturingProperty::BumpTexture || + i == Nif::NiTexturingProperty::GlowTexture) + continue; + if(!texName[i].empty()) + warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); + } + + if (vertexColour) + instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); + + // Add transparency if NiAlphaProperty was present + NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); + if (result.first) + { + alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ + alphaTest = result.second; + depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on + } + + if((alphaFlags&1)) + { + std::string blend_mode; + blend_mode += getBlendFactor((alphaFlags>>1)&0xf); + blend_mode += " "; + blend_mode += getBlendFactor((alphaFlags>>5)&0xf); + instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); + } + + if((alphaFlags>>9)&1) + { + std::string reject; + reject += getTestMode((alphaFlags>>10)&0x7); + reject += " "; + reject += Ogre::StringConverter::toString(alphaTest); + instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); + } + else + instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); + + // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" + instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( + ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); + + instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); + instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); + // depth_func??? + + sh::Factory::getInstance()._ensureMaterial(name, "Default"); + return name; +} + +std::map NIFMaterialLoader::sMaterialMap; + +} diff --git a/components/nifogre/material.hpp b/components/nifogre/material.hpp new file mode 100644 index 0000000000..8843ac6c6c --- /dev/null +++ b/components/nifogre/material.hpp @@ -0,0 +1,57 @@ +#ifndef COMPONENTS_NIFOGRE_MATERIAL_HPP +#define COMPONENTS_NIFOGRE_MATERIAL_HPP + +#include +#include +#include +#include + +#include + +namespace Nif +{ + class ShapeData; + class NiTexturingProperty; + class NiMaterialProperty; + class NiAlphaProperty; + class NiVertexColorProperty; + class NiZBufferProperty; + class NiSpecularProperty; + class NiWireframeProperty; +} + +namespace NifOgre +{ + +class NIFMaterialLoader { + static void warn(const std::string &msg) + { + std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; + abort(); + } + + static std::map sMaterialMap; + + static std::string findTextureName(const std::string &filename); + +public: + static Ogre::String getMaterial(const Nif::ShapeData *shapedata, + const Ogre::String &name, const Ogre::String &group, + const Nif::NiTexturingProperty *texprop, + const Nif::NiMaterialProperty *matprop, + const Nif::NiAlphaProperty *alphaprop, + const Nif::NiVertexColorProperty *vertprop, + const Nif::NiZBufferProperty *zprop, + const Nif::NiSpecularProperty *specprop, + const Nif::NiWireframeProperty *wireprop, + bool &needTangents); +}; + +} + +#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 0a30f38bd1..3bd93a1b9f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -40,18 +40,11 @@ #include #include -#include -#include -#include - -#include - #include #include -#include -#include #include "skeleton.hpp" +#include "material.hpp" namespace std { @@ -424,404 +417,6 @@ public: }; -// Conversion of blend / test mode from NIF -static const char *getBlendFactor(int mode) -{ - switch(mode) - { - case 0: return "one"; - case 1: return "zero"; - case 2: return "src_colour"; - case 3: return "one_minus_src_colour"; - case 4: return "dest_colour"; - case 5: return "one_minus_dest_colour"; - case 6: return "src_alpha"; - case 7: return "one_minus_src_alpha"; - case 8: return "dest_alpha"; - case 9: return "one_minus_dest_alpha"; - case 10: return "src_alpha_saturate"; - } - std::cerr<< "Unexpected blend mode: "< MaterialMap; - -static void warn(const std::string &msg) -{ - std::cerr << "NIFMaterialLoader: Warn: " << msg << std::endl; -} - -static void fail(const std::string &msg) -{ - std::cerr << "NIFMaterialLoader: Fail: "<< msg << std::endl; - abort(); -} - - -static std::string findTextureName(const std::string &filename) -{ - /* Bethesda at some point converted all their BSA - * textures from tga to dds for increased load speed, but all - * texture file name references were kept as .tga. - */ - static const char path[] = "textures\\"; - static const char path2[] = "textures/"; - - - std::string texname = filename; - Misc::StringUtils::toLower(texname); - - if(texname.compare(0, sizeof(path)-1, path) != 0 - && texname.compare(0, sizeof(path2)-1, path2) != 0) - texname = path + texname; - - Ogre::String::size_type pos = texname.rfind('.'); - if(pos != Ogre::String::npos && texname.compare(pos, texname.length() - pos, ".dds") != 0) - { - // since we know all (GOTY edition or less) textures end - // in .dds, we change the extension - texname.replace(pos, texname.length(), ".dds"); - - // if it turns out that the above wasn't true in all cases (not for vanilla, but maybe mods) - // verify, and revert if false (this call succeeds quickly, but fails slowly) - if(!Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(texname)) - { - texname = filename; - Misc::StringUtils::toLower(texname); - if(texname.compare(0, sizeof(path)-1, path) != 0 - && texname.compare(0, sizeof(path2)-1, path2) != 0) - texname = path + texname; - } - } - - return texname; -} - -public: -static Ogre::String getMaterial(const Nif::ShapeData *shapedata, - const Ogre::String &name, const Ogre::String &group, - const Nif::NiTexturingProperty *texprop, - const Nif::NiMaterialProperty *matprop, - const Nif::NiAlphaProperty *alphaprop, - const Nif::NiVertexColorProperty *vertprop, - const Nif::NiZBufferProperty *zprop, - const Nif::NiSpecularProperty *specprop, - const Nif::NiWireframeProperty *wireprop, - bool &needTangents) -{ - Ogre::MaterialManager &matMgr = Ogre::MaterialManager::getSingleton(); - Ogre::MaterialPtr material = matMgr.getByName(name); - if(!material.isNull()) - return name; - - Ogre::Vector3 ambient(1.0f); - Ogre::Vector3 diffuse(1.0f); - Ogre::Vector3 specular(0.0f); - Ogre::Vector3 emissive(0.0f); - float glossiness = 0.0f; - float alpha = 1.0f; - int alphaFlags = 0; - int alphaTest = 0; - int vertMode = 2; - //int lightMode = 1; - int depthFlags = 3; - // Default should be 1, but Bloodmoon's models are broken - int specFlags = 0; - int wireFlags = 0; - Ogre::String texName[7]; - - bool vertexColour = (shapedata->colors.size() != 0); - - // Texture - if(texprop) - { - for(int i = 0;i < 7;i++) - { - if(!texprop->textures[i].inUse) - continue; - if(texprop->textures[i].texture.empty()) - { - warn("Texture layer "+Ogre::StringConverter::toString(i)+" is in use but empty in "+name); - continue; - } - - const Nif::NiSourceTexture *st = texprop->textures[i].texture.getPtr(); - if(st->external) - texName[i] = findTextureName(st->filename); - else - warn("Found internal texture, ignoring."); - } - - Nif::ControllerPtr ctrls = texprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled texture controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - needTangents = !texName[Nif::NiTexturingProperty::BumpTexture].empty(); - - // Alpha modifiers - if(alphaprop) - { - alphaFlags = alphaprop->flags; - alphaTest = alphaprop->data.threshold; - - Nif::ControllerPtr ctrls = alphaprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled alpha controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Vertex color handling - if(vertprop) - { - vertMode = vertprop->data.vertmode; - // FIXME: Handle lightmode? - //lightMode = vertprop->data.lightmode; - - Nif::ControllerPtr ctrls = vertprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled vertex color controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(zprop) - { - depthFlags = zprop->flags; - // Depth function??? - - Nif::ControllerPtr ctrls = zprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled depth controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(specprop) - { - specFlags = specprop->flags; - - Nif::ControllerPtr ctrls = specprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled specular controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - if(wireprop) - { - wireFlags = wireprop->flags; - - Nif::ControllerPtr ctrls = wireprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled wireframe controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - // Material - if(matprop) - { - ambient = matprop->data.ambient; - diffuse = matprop->data.diffuse; - specular = matprop->data.specular; - emissive = matprop->data.emissive; - glossiness = matprop->data.glossiness; - alpha = matprop->data.alpha; - - Nif::ControllerPtr ctrls = matprop->controller; - while(!ctrls.empty()) - { - warn("Unhandled material controller "+ctrls->recName+" in "+name); - ctrls = ctrls->next; - } - } - - { - // Generate a hash out of all properties that can affect the material. - size_t h = 0; - boost::hash_combine(h, ambient.x); - boost::hash_combine(h, ambient.y); - boost::hash_combine(h, ambient.z); - boost::hash_combine(h, diffuse.x); - boost::hash_combine(h, diffuse.y); - boost::hash_combine(h, diffuse.z); - boost::hash_combine(h, alpha); - boost::hash_combine(h, specular.x); - boost::hash_combine(h, specular.y); - boost::hash_combine(h, specular.z); - boost::hash_combine(h, glossiness); - boost::hash_combine(h, emissive.x); - boost::hash_combine(h, emissive.y); - boost::hash_combine(h, emissive.z); - for(int i = 0;i < 7;i++) - { - if(!texName[i].empty()) - boost::hash_combine(h, texName[i]); - } - boost::hash_combine(h, vertexColour); - boost::hash_combine(h, alphaFlags); - boost::hash_combine(h, alphaTest); - boost::hash_combine(h, vertMode); - boost::hash_combine(h, depthFlags); - boost::hash_combine(h, specFlags); - boost::hash_combine(h, wireFlags); - - std::map::iterator itr = MaterialMap.find(h); - if (itr != MaterialMap.end()) - { - // a suitable material exists already - use it - return itr->second; - } - // not found, create a new one - MaterialMap.insert(std::make_pair(h, name)); - } - - // No existing material like this. Create a new one. - sh::MaterialInstance *instance = sh::Factory::getInstance().createMaterialInstance(name, "openmw_objects_base"); - if(vertMode == 0 || !vertexColour) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("0"))); - } - else if(vertMode == 1) - { - instance->setProperty("ambient", sh::makeProperty(new sh::Vector4(ambient.x, ambient.y, ambient.z, 1))); - instance->setProperty("diffuse", sh::makeProperty(new sh::Vector4(diffuse.x, diffuse.y, diffuse.z, alpha))); - instance->setProperty("emissive", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("1"))); - } - else if(vertMode == 2) - { - instance->setProperty("ambient", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("diffuse", sh::makeProperty(new sh::StringValue("vertexcolour"))); - instance->setProperty("emissive", sh::makeProperty(new sh::Vector4(emissive.x, emissive.y, emissive.z, 1))); - instance->setProperty("vertmode", sh::makeProperty(new sh::StringValue("2"))); - } - else - std::cerr<< "Unhandled vertex mode: "<setProperty("specular", sh::makeProperty( - new sh::Vector4(specular.x, specular.y, specular.z, glossiness))); - } - - if(wireFlags) - { - instance->setProperty("polygon_mode", sh::makeProperty(new sh::StringValue("wireframe"))); - } - - instance->setProperty("diffuseMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BaseTexture])); - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture])); - instance->setProperty("detailMap", sh::makeProperty(texName[Nif::NiTexturingProperty::DetailTexture])); - instance->setProperty("emissiveMap", sh::makeProperty(texName[Nif::NiTexturingProperty::GlowTexture])); - if (!texName[Nif::NiTexturingProperty::GlowTexture].empty()) - { - instance->setProperty("use_emissive_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("emissiveMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::GlowTexture].uvSet))); - } - if (!texName[Nif::NiTexturingProperty::DetailTexture].empty()) - { - instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); - instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); - } - if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) - { - // force automips on normal maps for now - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); - } - - for(int i = 0;i < 7;i++) - { - if(i == Nif::NiTexturingProperty::BaseTexture || - i == Nif::NiTexturingProperty::DetailTexture || - i == Nif::NiTexturingProperty::BumpTexture || - i == Nif::NiTexturingProperty::GlowTexture) - continue; - if(!texName[i].empty()) - warn("Ignored texture "+texName[i]+" on layer "+Ogre::StringConverter::toString(i)); - } - - if (vertexColour) - instance->setProperty("has_vertex_colour", sh::makeProperty(new sh::BooleanValue(true))); - - // Add transparency if NiAlphaProperty was present - NifOverrides::TransparencyResult result = NifOverrides::Overrides::getTransparencyOverride(texName[0]); - if (result.first) - { - alphaFlags = (1<<9) | (6<<10); /* alpha_rejection enabled, greater_equal */ - alphaTest = result.second; - depthFlags = (1<<0) | (1<<1); // depth_write on, depth_check on - } - - if((alphaFlags&1)) - { - std::string blend_mode; - blend_mode += getBlendFactor((alphaFlags>>1)&0xf); - blend_mode += " "; - blend_mode += getBlendFactor((alphaFlags>>5)&0xf); - instance->setProperty("scene_blend", sh::makeProperty(new sh::StringValue(blend_mode))); - } - - if((alphaFlags>>9)&1) - { - std::string reject; - reject += getTestMode((alphaFlags>>10)&0x7); - reject += " "; - reject += Ogre::StringConverter::toString(alphaTest); - instance->setProperty("alpha_rejection", sh::makeProperty(new sh::StringValue(reject))); - } - else - instance->getMaterial()->setShadowCasterMaterial("openmw_shadowcaster_noalpha"); - - // Ogre usually only sorts if depth write is disabled, so we want "force" instead of "on" - instance->setProperty("transparent_sorting", sh::makeProperty(new sh::StringValue( - ((alphaFlags&1) && !((alphaFlags>>13)&1)) ? "force" : "off"))); - - instance->setProperty("depth_check", sh::makeProperty(new sh::StringValue((depthFlags&1) ? "on" : "off"))); - instance->setProperty("depth_write", sh::makeProperty(new sh::StringValue(((depthFlags>>1)&1) ? "on" : "off"))); - // depth_func??? - - sh::Factory::getInstance()._ensureMaterial(name, "Default"); - return name; -} - -}; -std::map NIFMaterialLoader::MaterialMap; - - /** Manual resource loader for NIF objects (meshes, particle systems, etc). * This is the main class responsible for translating the internal NIF * structures into something Ogre can use. From 6128b9276f35d75c6fccb5a05e458fc8537ac5bc Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Thu, 11 Apr 2013 00:21:56 -0400 Subject: [PATCH 0394/1537] Removed non-essential includes from all MWGui header files. --- apps/openmw/mwgui/alchemywindow.hpp | 2 +- apps/openmw/mwgui/charactercreation.hpp | 4 ---- apps/openmw/mwgui/container.hpp | 3 --- apps/openmw/mwgui/cursor.hpp | 1 - apps/openmw/mwgui/dialogue.hpp | 3 --- apps/openmw/mwgui/dialoguehistory.hpp | 1 + apps/openmw/mwgui/enchantingdialog.hpp | 2 -- apps/openmw/mwgui/hud.hpp | 2 -- apps/openmw/mwgui/itemselection.hpp | 2 -- apps/openmw/mwgui/journalwindow.hpp | 3 --- apps/openmw/mwgui/list.hpp | 1 - apps/openmw/mwgui/loadingscreen.hpp | 1 - apps/openmw/mwgui/messagebox.hpp | 2 -- apps/openmw/mwgui/quickkeysmenu.hpp | 1 - apps/openmw/mwgui/race.hpp | 5 ----- apps/openmw/mwgui/repair.hpp | 1 - apps/openmw/mwgui/review.hpp | 1 - apps/openmw/mwgui/statswindow.hpp | 5 ----- apps/openmw/mwgui/tradewindow.hpp | 3 --- apps/openmw/mwgui/travelwindow.hpp | 3 --- apps/openmw/mwgui/widgets.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.hpp | 5 ----- 22 files changed, 2 insertions(+), 51 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index c61d2f92b3..655a832c17 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -5,12 +5,12 @@ #include "../mwmechanics/alchemy.hpp" -#include "windowbase.hpp" #include "container.hpp" #include "widgets.hpp" namespace MWGui { + class AlchemyWindow : public WindowBase, public ContainerBase { public: diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index fed77e889f..586faf966e 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -1,13 +1,9 @@ #ifndef CHARACTER_CREATION_HPP #define CHARACTER_CREATION_HPP -#include "../mwworld/esmstore.hpp" - #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/stat.hpp" - namespace MWGui { class WindowBase; diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 521ac8cc35..8440c6444e 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -1,13 +1,10 @@ #ifndef MGUI_CONTAINER_H #define MGUI_CONTAINER_H -#include "../mwworld/esmstore.hpp" - #include "windowbase.hpp" #include "referenceinterface.hpp" #include "../mwclass/container.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/containerstore.hpp" diff --git a/apps/openmw/mwgui/cursor.hpp b/apps/openmw/mwgui/cursor.hpp index 3a4a05f4ca..badf82262b 100644 --- a/apps/openmw/mwgui/cursor.hpp +++ b/apps/openmw/mwgui/cursor.hpp @@ -3,7 +3,6 @@ #include #include -#include namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a1bbee02c7..74fa8051c5 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -3,9 +3,6 @@ #include "windowbase.hpp" #include "referenceinterface.hpp" -#include - -#include "../mwworld/ptr.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/dialoguehistory.hpp b/apps/openmw/mwgui/dialoguehistory.hpp index c37504af77..4cf6de621d 100644 --- a/apps/openmw/mwgui/dialoguehistory.hpp +++ b/apps/openmw/mwgui/dialoguehistory.hpp @@ -1,5 +1,6 @@ #ifndef MWGUI_DIALOGE_HISTORY_H #define MWGUI_DIALOGE_HISTORY_H + #include namespace MWGui diff --git a/apps/openmw/mwgui/enchantingdialog.hpp b/apps/openmw/mwgui/enchantingdialog.hpp index c727a09749..8bad60c8e6 100644 --- a/apps/openmw/mwgui/enchantingdialog.hpp +++ b/apps/openmw/mwgui/enchantingdialog.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_ENCHANTINGDIALOG_H #define MWGUI_ENCHANTINGDIALOG_H -#include "windowbase.hpp" -#include "referenceinterface.hpp" #include "spellcreationdialog.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index c65566ce3e..1dd53683b8 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -1,7 +1,5 @@ #include "mapwindow.hpp" -#include - #include "../mwmechanics/stat.hpp" #include "../mwworld/ptr.hpp" diff --git a/apps/openmw/mwgui/itemselection.hpp b/apps/openmw/mwgui/itemselection.hpp index 3e812d26c5..19007de6b0 100644 --- a/apps/openmw/mwgui/itemselection.hpp +++ b/apps/openmw/mwgui/itemselection.hpp @@ -1,7 +1,5 @@ #include "container.hpp" -#include "../mwworld/ptr.hpp" - namespace MWGui { diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 7670b65f55..da05a6f0ec 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,10 +1,7 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include -#include #include -#include #include "windowbase.hpp" #include "imagebutton.hpp" diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index 09e42e865e..956523c0dc 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_LIST_HPP #define MWGUI_LIST_HPP -#include #include namespace MWGui diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index 12e6504bca..87cedaa98c 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -2,7 +2,6 @@ #define MWGUI_LOADINGSCREEN_H #include -#include #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/messagebox.hpp b/apps/openmw/mwgui/messagebox.hpp index cb40739023..0df6f3544b 100644 --- a/apps/openmw/mwgui/messagebox.hpp +++ b/apps/openmw/mwgui/messagebox.hpp @@ -1,8 +1,6 @@ #ifndef MWGUI_MESSAGE_BOX_H #define MWGUI_MESSAGE_BOX_H -#include - #include "windowbase.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 646ec2aa45..058519ece4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -1,7 +1,6 @@ #ifndef MWGUI_QUICKKEYS_H #define MWGUI_QUICKKEYS_H - #include "../mwworld/ptr.hpp" #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index f3adce4447..893c4c90b6 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -1,11 +1,6 @@ #ifndef MWGUI_RACE_H #define MWGUI_RACE_H - -#include - -#include "../mwworld/esmstore.hpp" - #include "../mwrender/characterpreview.hpp" #include "windowbase.hpp" diff --git a/apps/openmw/mwgui/repair.hpp b/apps/openmw/mwgui/repair.hpp index 5d9a487199..d0f5c54c4b 100644 --- a/apps/openmw/mwgui/repair.hpp +++ b/apps/openmw/mwgui/repair.hpp @@ -3,7 +3,6 @@ #include "windowbase.hpp" -#include "../mwworld/ptr.hpp" #include "../mwmechanics/repair.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index d5df94e285..87d6fedfa7 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -2,7 +2,6 @@ #define MWGUI_REVIEW_H #include "windowbase.hpp" -#include "../mwmechanics/stat.hpp" #include "widgets.hpp" namespace MWGui diff --git a/apps/openmw/mwgui/statswindow.hpp b/apps/openmw/mwgui/statswindow.hpp index 4b723048cc..bec42d029b 100644 --- a/apps/openmw/mwgui/statswindow.hpp +++ b/apps/openmw/mwgui/statswindow.hpp @@ -3,11 +3,6 @@ #include "../mwworld/esmstore.hpp" -#include -#include -#include -#include - #include "../mwmechanics/stat.hpp" #include "windowpinnablebase.hpp" diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp index e526a42ca5..892ce0297c 100644 --- a/apps/openmw/mwgui/tradewindow.hpp +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -2,9 +2,6 @@ #define MWGUI_TRADEWINDOW_H #include "container.hpp" -#include "windowbase.hpp" - -#include "../mwworld/ptr.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/travelwindow.hpp b/apps/openmw/mwgui/travelwindow.hpp index a814d04785..f2a23b0486 100644 --- a/apps/openmw/mwgui/travelwindow.hpp +++ b/apps/openmw/mwgui/travelwindow.hpp @@ -2,9 +2,6 @@ #define MWGUI_TravelWINDOW_H #include "container.hpp" -#include "windowbase.hpp" - -#include "../mwworld/ptr.hpp" namespace MyGUI { diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 038ce3f86f..1567946913 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -4,8 +4,6 @@ #include "../mwworld/esmstore.hpp" #include "../mwmechanics/stat.hpp" -#include -#include #include #include diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a3..652ad870f3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -10,11 +10,6 @@ this class. **/ -#include -#include - -#include - #include "../mwbase/windowmanager.hpp" namespace MyGUI From 62e0abd94582060951c887ac6a1782ea1644aa2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 22:38:46 -0700 Subject: [PATCH 0395/1537] Move the mesh loader to its own source file --- components/CMakeLists.txt | 2 +- components/nifogre/mesh.cpp | 375 +++++++++++++++++++ components/nifogre/mesh.hpp | 55 +++ components/nifogre/ogrenifloader.cpp | 526 +++++---------------------- 4 files changed, 516 insertions(+), 442 deletions(-) create mode 100644 components/nifogre/mesh.cpp create mode 100644 components/nifogre/mesh.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index aa422b49e7..dd8f78eda6 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -19,7 +19,7 @@ add_component_dir (nif ) add_component_dir (nifogre - ogrenifloader skeleton material + ogrenifloader skeleton material mesh ) add_component_dir (nifbullet diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp new file mode 100644 index 0000000000..3780306f6d --- /dev/null +++ b/components/nifogre/mesh.cpp @@ -0,0 +1,375 @@ +#include "mesh.hpp" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "material.hpp" + +namespace NifOgre +{ + +void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop); + +// Helper class that computes the bounding box and of a mesh +class BoundsFinder +{ + struct MaxMinFinder + { + float max, min; + + MaxMinFinder() + { + min = std::numeric_limits::infinity(); + max = -min; + } + + void add(float f) + { + if (f > max) max = f; + if (f < min) min = f; + } + + // Return Max(max**2, min**2) + float getMaxSquared() + { + float m1 = max*max; + float m2 = min*min; + if (m1 >= m2) return m1; + return m2; + } + }; + + MaxMinFinder X, Y, Z; + +public: + // Add 'verts' vertices to the calculation. The 'data' pointer is + // expected to point to 3*verts floats representing x,y,z for each + // point. + void add(float *data, int verts) + { + for (int i=0;idata.getPtr(); + const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); + std::vector srcVerts = data->vertices; + std::vector srcNorms = data->normals; + Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; + bool vertShadowBuffer = false; + if(skin != NULL) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + + // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be + // explicitly attached later. + mesh->setSkeletonName(mName); + + // Get the skeleton resource, so vertices can be transformed into the bones' initial state. + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + skel = skelMgr->getByName(mName); + + // Convert vertices and normals to bone space from bind position. It would be + // better to transform the bones into bind position, but there doesn't seem to + // be a reliable way to do that. + std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); + std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); + + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t b = 0;b < bones.length();b++) + { + Ogre::Bone *bone = skel->getBone(bones[b]->name); + Ogre::Matrix4 mat; + mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), + Ogre::Quaternion(data->bones[b].trafo.rotation)); + mat = bone->_getFullTransform() * mat; + + const std::vector &weights = data->bones[b].weights; + for(size_t i = 0;i < weights.size();i++) + { + size_t index = weights[i].vertex; + float weight = weights[i].weight; + + newVerts.at(index) += (mat*srcVerts[index]) * weight; + if(newNorms.size() > index) + { + Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); + vec4 = mat*vec4 * weight; + newNorms[index] += Ogre::Vector3(&vec4[0]); + } + } + } + + srcVerts = newVerts; + srcNorms = newNorms; + } + else + { + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(skelMgr->getByName(mName).isNull()) + { + // No skinning and no skeleton, so just transform the vertices and + // normals into position. + Ogre::Matrix4 mat4 = shape->getWorldTransform(); + for(size_t i = 0;i < srcVerts.size();i++) + { + Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); + vec4 = mat4*vec4; + srcVerts[i] = Ogre::Vector3(&vec4[0]); + } + for(size_t i = 0;i < srcNorms.size();i++) + { + Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); + vec4 = mat4*vec4; + srcNorms[i] = Ogre::Vector3(&vec4[0]); + } + } + } + + // Set the bounding box first + BoundsFinder bounds; + bounds.add(&srcVerts[0][0], srcVerts.size()); + if(!bounds.isValid()) + { + float v[3] = { 0.0f, 0.0f, 0.0f }; + bounds.add(&v[0], 1); + } + + mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, + bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); + mesh->_setBoundingSphereRadius(bounds.getRadius()); + + // This function is just one long stream of Ogre-barf, but it works + // great. + Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); + Ogre::HardwareVertexBufferSharedPtr vbuf; + Ogre::HardwareIndexBufferSharedPtr ibuf; + Ogre::VertexBufferBinding *bind; + Ogre::VertexDeclaration *decl; + int nextBuf = 0; + + Ogre::SubMesh *sub = mesh->createSubMesh(); + + // Add vertices + sub->useSharedVertices = false; + sub->vertexData = new Ogre::VertexData(); + sub->vertexData->vertexStart = 0; + sub->vertexData->vertexCount = srcVerts.size(); + + decl = sub->vertexData->vertexDeclaration; + bind = sub->vertexData->vertexBufferBinding; + if(srcVerts.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcVerts.size(), vertUsage, vertShadowBuffer); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex normals + if(srcNorms.size()) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), + srcNorms.size(), vertUsage, vertShadowBuffer); + vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); + bind->setBinding(nextBuf++, vbuf); + } + + // Vertex colors + const std::vector &colors = data->colors; + if(colors.size()) + { + Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem(); + std::vector colorsRGB(colors.size()); + for(size_t i = 0;i < colorsRGB.size();i++) + { + Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); + rs->convertColourValue(clr, &colorsRGB[i]); + } + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), + colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); + decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); + bind->setBinding(nextBuf++, vbuf); + } + + // Texture UV coordinates + size_t numUVs = data->uvlist.size(); + for(size_t i = 0;i < numUVs;i++) + { + vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), + srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); + vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + + decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + bind->setBinding(nextBuf++, vbuf); + } + + // Triangle faces + const std::vector &srcIdx = data->triangles; + if(srcIdx.size()) + { + ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), + Ogre::HardwareBuffer::HBU_STATIC); + ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); + sub->indexData->indexBuffer = ibuf; + sub->indexData->indexCount = srcIdx.size(); + sub->indexData->indexStart = 0; + } + + // Assign bone weights for this TriShape + if(skin != NULL) + { + const Nif::NiSkinData *data = skin->data.getPtr(); + const Nif::NodeList &bones = skin->bones; + for(size_t i = 0;i < bones.length();i++) + { + Ogre::VertexBoneAssignment boneInf; + boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); + + const std::vector &weights = data->bones[i].weights; + for(size_t j = 0;j < weights.size();j++) + { + boneInf.vertexIndex = weights[j].vertex; + boneInf.weight = weights[j].weight; + sub->addBoneAssignment(boneInf); + } + } + } + + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; + + getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents); + if(matname.length() > 0) + sub->setMaterialName(matname); + + // build tangents if the material needs them + if (needTangents) + { + unsigned short src,dest; + if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) + mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); + } +} + + +NIFMeshLoader::NIFMeshLoader(const std::string &name, const std::string &group, size_t idx) + : mName(name), mGroup(group), mShapeIndex(idx) +{ +} + +void NIFMeshLoader::loadResource(Ogre::Resource *resource) +{ + Ogre::Mesh *mesh = dynamic_cast(resource); + OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); + + Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); + if(mShapeIndex >= nif->numRecords()) + { + Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); + if(!skelMgr->getByName(mName).isNull()) + mesh->setSkeletonName(mName); + return; + } + + const Nif::Record *record = nif->getRecord(mShapeIndex); + createSubMesh(mesh, dynamic_cast(record)); +} + + +void NIFMeshLoader::createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx) +{ + NIFMeshLoader::LoaderMap::iterator loader; + loader = sLoaders.insert(std::make_pair(fullname, NIFMeshLoader(name, group, idx))).first; + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + Ogre::MeshPtr mesh = meshMgr.createManual(fullname, group, &loader->second); + mesh->setAutoBuildEdgeLists(false); +} + +} diff --git a/components/nifogre/mesh.hpp b/components/nifogre/mesh.hpp new file mode 100644 index 0000000000..731e49c903 --- /dev/null +++ b/components/nifogre/mesh.hpp @@ -0,0 +1,55 @@ +#ifndef COMPONENTS_NIFOGRE_MESH_HPP +#define COMPONENTS_NIFOGRE_MESH_HPP + +#include +#include +#include +#include + +#include + +namespace Nif +{ + class NiTriShape; +} + +namespace NifOgre +{ + +/** Manual resource loader for NiTriShapes. This is the main class responsible + * for translating the internal NIF meshes into something Ogre can use. + */ +class NIFMeshLoader : Ogre::ManualResourceLoader +{ + static void warn(const std::string &msg) + { + std::cerr << "NIFMeshLoader: Warn: " << msg << std::endl; + } + + static void fail(const std::string &msg) + { + std::cerr << "NIFMeshLoader: Fail: "<< msg << std::endl; + abort(); + } + + std::string mName; + std::string mGroup; + size_t mShapeIndex; + + // Convert NiTriShape to Ogre::SubMesh + void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape); + + typedef std::map LoaderMap; + static LoaderMap sLoaders; + + NIFMeshLoader(const std::string &name, const std::string &group, size_t idx); + + virtual void loadResource(Ogre::Resource *resource); + +public: + static void createMesh(const std::string &name, const std::string &fullname, const std::string &group, size_t idx); +}; + +} + +#endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 3bd93a1b9f..8d82c3ced7 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -25,12 +25,7 @@ #include -#include -#include -#include -#include #include -#include #include #include #include @@ -38,6 +33,8 @@ #include #include #include +#include +#include #include #include @@ -45,6 +42,7 @@ #include "skeleton.hpp" #include "material.hpp" +#include "mesh.hpp" namespace std { @@ -58,6 +56,46 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { +void getNodeProperties(const Nif::Node *node, + const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) +{ + if(node->parent) + getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + const Nif::PropertyList &proplist = node->props; + for(size_t i = 0;i < proplist.length();i++) + { + // Entries may be empty + if(proplist[i].empty()) + continue; + + const Nif::Property *pr = proplist[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName < { @@ -332,101 +370,13 @@ public: }; -// Helper class that computes the bounding box and of a mesh -class BoundsFinder -{ - struct MaxMinFinder - { - float max, min; - - MaxMinFinder() - { - min = std::numeric_limits::infinity(); - max = -min; - } - - void add(float f) - { - if (f > max) max = f; - if (f < min) min = f; - } - - // Return Max(max**2, min**2) - float getMaxSquared() - { - float m1 = max*max; - float m2 = min*min; - if (m1 >= m2) return m1; - return m2; - } - }; - - MaxMinFinder X, Y, Z; - -public: - // Add 'verts' vertices to the calculation. The 'data' pointer is - // expected to point to 3*verts floats representing x,y,z for each - // point. - void add(float *data, int verts) - { - for (int i=0;iparent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - warn("Unhandled property type: "+pr->recName); - } - } - - // Convert NiTriShape to Ogre::SubMesh - void createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) - { - Ogre::SkeletonPtr skel; - const Nif::NiTriShapeData *data = shape->data.getPtr(); - const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); - std::vector srcVerts = data->vertices; - std::vector srcNorms = data->normals; - Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; - bool vertShadowBuffer = false; - if(skin != NULL) - { - vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; - vertShadowBuffer = true; - - // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be - // explicitly attached later. - mesh->setSkeletonName(mName); - - // Get the skeleton resource, so vertices can be transformed into the bones' initial state. - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mName); - - // Convert vertices and normals to bone space from bind position. It would be - // better to transform the bones into bind position, but there doesn't seem to - // be a reliable way to do that. - std::vector newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); - std::vector newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); - - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t b = 0;b < bones.length();b++) - { - Ogre::Bone *bone = skel->getBone(bones[b]->name); - Ogre::Matrix4 mat; - mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), - Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; - - const std::vector &weights = data->bones[b].weights; - for(size_t i = 0;i < weights.size();i++) - { - size_t index = weights[i].vertex; - float weight = weights[i].weight; - - newVerts.at(index) += (mat*srcVerts[index]) * weight; - if(newNorms.size() > index) - { - Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); - vec4 = mat*vec4 * weight; - newNorms[index] += Ogre::Vector3(&vec4[0]); - } - } - } - - srcVerts = newVerts; - srcNorms = newNorms; - } - else - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(skelMgr->getByName(mName).isNull()) - { - // No skinning and no skeleton, so just transform the vertices and - // normals into position. - Ogre::Matrix4 mat4 = shape->getWorldTransform(); - for(size_t i = 0;i < srcVerts.size();i++) - { - Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); - vec4 = mat4*vec4; - srcVerts[i] = Ogre::Vector3(&vec4[0]); - } - for(size_t i = 0;i < srcNorms.size();i++) - { - Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); - vec4 = mat4*vec4; - srcNorms[i] = Ogre::Vector3(&vec4[0]); - } - } - } - - // Set the bounding box first - BoundsFinder bounds; - bounds.add(&srcVerts[0][0], srcVerts.size()); - if(!bounds.isValid()) - { - float v[3] = { 0.0f, 0.0f, 0.0f }; - bounds.add(&v[0], 1); - } - - mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, - bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); - mesh->_setBoundingSphereRadius(bounds.getRadius()); - - // This function is just one long stream of Ogre-barf, but it works - // great. - Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); - Ogre::HardwareVertexBufferSharedPtr vbuf; - Ogre::HardwareIndexBufferSharedPtr ibuf; - Ogre::VertexBufferBinding *bind; - Ogre::VertexDeclaration *decl; - int nextBuf = 0; - - Ogre::SubMesh *sub = mesh->createSubMesh(); - - // Add vertices - sub->useSharedVertices = false; - sub->vertexData = new Ogre::VertexData(); - sub->vertexData->vertexStart = 0; - sub->vertexData->vertexCount = srcVerts.size(); - - decl = sub->vertexData->vertexDeclaration; - bind = sub->vertexData->vertexBufferBinding; - if(srcVerts.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcVerts.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex normals - if(srcNorms.size()) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), - srcNorms.size(), vertUsage, vertShadowBuffer); - vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); - bind->setBinding(nextBuf++, vbuf); - } - - // Vertex colors - const std::vector &colors = data->colors; - if(colors.size()) - { - Ogre::RenderSystem* rs = Ogre::Root::getSingleton().getRenderSystem(); - std::vector colorsRGB(colors.size()); - for(size_t i = 0;i < colorsRGB.size();i++) - { - Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); - rs->convertColourValue(clr, &colorsRGB[i]); - } - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), - colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); - bind->setBinding(nextBuf++, vbuf); - } - - // Texture UV coordinates - size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) - { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); - - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); - bind->setBinding(nextBuf++, vbuf); - } - - // Triangle faces - const std::vector &srcIdx = data->triangles; - if(srcIdx.size()) - { - ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), - Ogre::HardwareBuffer::HBU_STATIC); - ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); - sub->indexData->indexBuffer = ibuf; - sub->indexData->indexCount = srcIdx.size(); - sub->indexData->indexStart = 0; - } - - // Assign bone weights for this TriShape - if(skin != NULL) - { - const Nif::NiSkinData *data = skin->data.getPtr(); - const Nif::NodeList &bones = skin->bones; - for(size_t i = 0;i < bones.length();i++) - { - Ogre::VertexBoneAssignment boneInf; - boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); - - const std::vector &weights = data->bones[i].weights; - for(size_t j = 0;j < weights.size();j++) - { - boneInf.vertexIndex = weights[j].vertex; - boneInf.weight = weights[j].weight; - sub->addBoneAssignment(boneInf); - } - } - } - - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; - - getNodeProperties(shape, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents); - if(matname.length() > 0) - sub->setMaterialName(matname); - - // build tangents if the material needs them - if (needTangents) - { - unsigned short src,dest; - if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) - mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); - } - } - - - typedef std::map LoaderMap; - static LoaderMap sLoaders; - static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { @@ -743,8 +428,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } } - Ogre::ParticleSystem *createParticleSystem(Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, + const Nif::Node *partnode) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -754,7 +440,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); try { - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); if(partnode->name.length() > 0) fullname += "@type="+partnode->name; Misc::StringUtils::toLower(fullname); @@ -769,7 +455,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader bool needTangents = false; getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, mGroup, + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, needTangents)); @@ -789,7 +475,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader createParticleEmitterAffectors(partsys, partctrl); if(!partctrl->emitter.empty() && !partsys->isAttached()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partctrl->emitter->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); entitybase->attachObjectToBone(trgtbone->getName(), partsys); } @@ -799,7 +485,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(!partsys->isAttached()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, partnode->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); entitybase->attachObjectToBone(trgtbone->getName(), partsys); } @@ -813,29 +499,9 @@ class NIFObjectLoader : Ogre::ManualResourceLoader } - NIFObjectLoader(const std::string &name, const std::string &group) - : mName(name), mGroup(group), mShapeIndex(~(size_t)0) - { } - - virtual void loadResource(Ogre::Resource *resource) - { - Ogre::Mesh *mesh = dynamic_cast(resource); - OgreAssert(mesh, "Attempting to load a mesh into a non-mesh resource!"); - - Nif::NIFFile::ptr nif = Nif::NIFFile::create(mName); - if(mShapeIndex >= nif->numRecords()) - { - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - if(!skelMgr->getByName(mName).isNull()) - mesh->setSkeletonName(mName); - return; - } - - const Nif::Record *record = nif->getRecord(mShapeIndex); - createSubMesh(mesh, dynamic_cast(record)); - } - - void createObjects(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags=0) + static void createObjects(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, const Nif::Node *node, + ObjectList &objectlist, int flags=0) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -868,7 +534,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiCamera) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, node->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mCameras.push_back(trgtbone); } @@ -880,7 +546,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader { const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::ControllerValueRealPtr srcval; /* Filled in later */ Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); @@ -893,7 +559,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); if(!key->data.empty()) { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, ctrl->target->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); Ogre::ControllerValueRealPtr srcval; /* Filled in later */ Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); @@ -909,24 +575,16 @@ class NIFObjectLoader : Ogre::ManualResourceLoader { const Nif::NiTriShape *shape = static_cast(node); - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - std::string fullname = mName+"@index="+Ogre::StringConverter::toString(shape->recIndex); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); if(shape->name.length() > 0) fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFObjectLoader *loader = &sLoaders[fullname]; - *loader = *this; - loader->mShapeIndex = shape->recIndex; - mesh = meshMgr.createManual(fullname, mGroup, loader); - mesh->setAutoBuildEdgeLists(false); - } + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - Ogre::Entity *entity = sceneMgr->createEntity(mesh); + Ogre::Entity *entity = sceneMgr->createEntity(fullname); entity->setVisible(!(flags&0x01)); objectlist.mEntities.push_back(entity); @@ -936,7 +594,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader entity->shareSkeletonInstanceWith(objectlist.mSkelBase); else { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(mName, shape->recIndex); + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); } @@ -963,7 +621,7 @@ class NIFObjectLoader : Ogre::ManualResourceLoader if(node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) { - Ogre::ParticleSystem *partsys = createParticleSystem(sceneMgr, objectlist.mSkelBase, node); + Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) { partsys->setVisible(!(flags&0x01)); @@ -978,71 +636,57 @@ class NIFObjectLoader : Ogre::ManualResourceLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); } } } - void createSkelBase(Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist) + static void createSkelBase(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, const Nif::Node *node, + ObjectList &objectlist) { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all * other meshes are hidden or entities attached to a specific node * instead of skinned. */ - std::string fullname = mName; - Misc::StringUtils::toLower(fullname); - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - Ogre::MeshPtr mesh = meshMgr.getByName(fullname); - if(mesh.isNull()) - { - NIFObjectLoader *loader = &sLoaders[fullname]; - *loader = *this; + if(meshMgr.getByName(name).isNull()) + NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); - mesh = meshMgr.createManual(fullname, mGroup, loader); - mesh->setAutoBuildEdgeLists(false); - } - objectlist.mSkelBase = sceneMgr->createEntity(mesh); + objectlist.mSkelBase = sceneMgr->createEntity(name); objectlist.mEntities.push_back(objectlist.mSkelBase); } public: - NIFObjectLoader() : mShapeIndex(~(size_t)0) - { } - static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) { - Nif::NIFFile::ptr pnif = Nif::NIFFile::create(name); - Nif::NIFFile &nif = *pnif.get(); - if(nif.numRoots() < 1) + Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); + if(nif->numRoots() < 1) { - nif.warn("Found no root nodes in "+name+"."); + nif->warn("Found no root nodes in "+name+"."); return; } - // The first record is assumed to be the root node - const Nif::Record *r = nif.getRoot(0); + const Nif::Record *r = nif->getRoot(0); assert(r != NULL); - const Nif::Node *node = dynamic_cast(r); + const Nif::Node *node = dynamic_cast(r); if(node == NULL) { - nif.warn("First root in "+name+" was not a node, but a "+ - r->recName+"."); + nif->warn("First root in "+name+" was not a node, but a "+ + r->recName+"."); return; } - bool hasSkel = Ogre::SkeletonManager::getSingleton().resourceExists(name); - if(!hasSkel) - hasSkel = !NIFSkeletonLoader::createSkeleton(name, group, node).isNull(); - - NIFObjectLoader meshldr(name, group); - if(hasSkel) - meshldr.createSkelBase(sceneMgr, node, objectlist); - meshldr.createObjects(sceneMgr, node, objectlist); + if(Ogre::SkeletonManager::getSingleton().resourceExists(name) || + !NIFSkeletonLoader::createSkeleton(name, group, node).isNull()) + { + // Create a base skeleton entity if this NIF needs one + createSkelBase(name, group, sceneMgr, node, objectlist); + } + createObjects(name, group, sceneMgr, node, objectlist); } }; -NIFObjectLoader::LoaderMap NIFObjectLoader::sLoaders; ObjectList Loader::createObjects(Ogre::SceneNode *parentNode, std::string name, const std::string &group) From d26ffe9de02dfd69a7477eae31349c6a9efbca94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 10 Apr 2013 23:19:47 -0700 Subject: [PATCH 0396/1537] Move a method to the Node class --- components/nif/niffile.cpp | 38 +++++++++++++++++++++++++ components/nif/node.hpp | 8 ++++++ components/nifogre/mesh.cpp | 11 +------- components/nifogre/ogrenifloader.cpp | 42 +--------------------------- 4 files changed, 48 insertions(+), 51 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 44eae2953d..3b41e96a70 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -384,6 +384,44 @@ void NiSkinInstance::post(NIFFile *nif) } } + +void Node::getProperties(const Nif::NiTexturingProperty *&texprop, + const Nif::NiMaterialProperty *&matprop, + const Nif::NiAlphaProperty *&alphaprop, + const Nif::NiVertexColorProperty *&vertprop, + const Nif::NiZBufferProperty *&zprop, + const Nif::NiSpecularProperty *&specprop, + const Nif::NiWireframeProperty *&wireprop) const +{ + if(parent) + parent->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + + for(size_t i = 0;i < props.length();i++) + { + // Entries may be empty + if(props[i].empty()) + continue; + + const Nif::Property *pr = props[i].getPtr(); + if(pr->recType == Nif::RC_NiTexturingProperty) + texprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiMaterialProperty) + matprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiAlphaProperty) + alphaprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiVertexColorProperty) + vertprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiZBufferProperty) + zprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiSpecularProperty) + specprop = static_cast(pr); + else if(pr->recType == Nif::RC_NiWireframeProperty) + wireprop = static_cast(pr); + else + std::cerr<< "Unhandled property type: "<recName <getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 8d82c3ced7..48893bf4a8 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -56,46 +56,6 @@ ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) namespace NifOgre { -void getNodeProperties(const Nif::Node *node, - const Nif::NiTexturingProperty *&texprop, - const Nif::NiMaterialProperty *&matprop, - const Nif::NiAlphaProperty *&alphaprop, - const Nif::NiVertexColorProperty *&vertprop, - const Nif::NiZBufferProperty *&zprop, - const Nif::NiSpecularProperty *&specprop, - const Nif::NiWireframeProperty *&wireprop) -{ - if(node->parent) - getNodeProperties(node->parent, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - - const Nif::PropertyList &proplist = node->props; - for(size_t i = 0;i < proplist.length();i++) - { - // Entries may be empty - if(proplist[i].empty()) - continue; - - const Nif::Property *pr = proplist[i].getPtr(); - if(pr->recType == Nif::RC_NiTexturingProperty) - texprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiMaterialProperty) - matprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiAlphaProperty) - alphaprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiVertexColorProperty) - vertprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiZBufferProperty) - zprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiSpecularProperty) - specprop = static_cast(pr); - else if(pr->recType == Nif::RC_NiWireframeProperty) - wireprop = static_cast(pr); - else - std::cerr<< "Unhandled property type: "<recName < { @@ -454,7 +414,7 @@ class NIFObjectLoader const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; - getNodeProperties(partnode, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, texprop, matprop, alphaprop, vertprop, zprop, specprop, From 6d3a2cd5a0c5364395cdad5aeedb291abeffc1e2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 10:50:22 +0200 Subject: [PATCH 0397/1537] added comment token (for use in syntax colouring) --- components/compiler/parser.cpp | 5 +++++ components/compiler/parser.hpp | 7 +++++++ components/compiler/scanner.cpp | 9 ++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/components/compiler/parser.cpp b/components/compiler/parser.cpp index 896458e482..8d11c4086d 100644 --- a/components/compiler/parser.cpp +++ b/components/compiler/parser.cpp @@ -148,6 +148,11 @@ namespace Compiler return false; } + bool Parser::parseComment (const std::string& comment, const TokenLoc& loc, Scanner& scanner) + { + return true; + } + // Handle an EOF token. // // - Default-implementation: Report an error. diff --git a/components/compiler/parser.hpp b/components/compiler/parser.hpp index 221e7c2c9f..4fec570e9f 100644 --- a/components/compiler/parser.hpp +++ b/components/compiler/parser.hpp @@ -82,6 +82,13 @@ namespace Compiler /// /// - Default-implementation: Report an error. + virtual bool parseComment (const std::string& comment, const TokenLoc& loc, + Scanner& scanner); + ///< Handle comment token. + /// \return fetch another token? + /// + /// - Default-implementation: ignored (and return true). + virtual void parseEOF (Scanner& scanner); ///< Handle EOF token. /// diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 420fd8f7f3..38a9265a1e 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -88,6 +88,10 @@ namespace Compiler } else if (c==';') { + std::string comment; + + comment += c; + while (get (c)) { if (c=='\n') @@ -95,11 +99,14 @@ namespace Compiler putback (c); break; } + else + comment += c; } + TokenLoc loc (mLoc); mLoc.mLiteral.clear(); - return true; + return parser.parseComment (comment, loc, *this); } else if (isWhitespace (c)) { From f17cebde0aea9e8cc1aaedd3592923eb5618c0fb Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 10:50:35 +0200 Subject: [PATCH 0398/1537] syntax colouring for comments --- apps/opencs/view/world/scripthighlighter.cpp | 15 ++++++++++++++- apps/opencs/view/world/scripthighlighter.hpp | 7 +++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index 1e93ac26b7..288a3d12ac 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -40,6 +40,13 @@ bool CSVWorld::ScriptHighlighter::parseSpecial (int code, const Compiler::TokenL return true; } +bool CSVWorld::ScriptHighlighter::parseComment (const std::string& comment, + const Compiler::TokenLoc& loc, Compiler::Scanner& scanner) +{ + highlight (loc, Type_Comment); + return true; +} + void CSVWorld::ScriptHighlighter::parseEOF (Compiler::Scanner& scanner) {} @@ -67,7 +74,7 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) { QTextCharFormat format; - format.setForeground (Qt::green); + format.setForeground (Qt::magenta); mScheme.insert (std::make_pair (Type_Float, format)); } @@ -88,6 +95,12 @@ CSVWorld::ScriptHighlighter::ScriptHighlighter (QTextDocument *parent) format.setForeground (Qt::darkYellow); mScheme.insert (std::make_pair (Type_Special, format)); } + + { + QTextCharFormat format; + format.setForeground (Qt::green); + mScheme.insert (std::make_pair (Type_Comment, format)); + } } void CSVWorld::ScriptHighlighter::highlightBlock (const QString& text) diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index e9918f99b7..3ef6978097 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -22,7 +22,8 @@ namespace CSVWorld Type_Float, Type_Name, Type_Keyword, - Type_Special + Type_Special, + Type_Comment }; private: @@ -58,7 +59,9 @@ namespace CSVWorld ///< Handle a special character token. /// \return fetch another token? - ///< Handle a special character token. + virtual bool parseComment (const std::string& comment, const Compiler::TokenLoc& loc, + Compiler::Scanner& scanner); + ///< Handle comment token. /// \return fetch another token? virtual void parseEOF (Compiler::Scanner& scanner); From 9c7ad758169c0a539b629540e3123348060505b2 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 11 Apr 2013 14:44:02 +0200 Subject: [PATCH 0399/1537] updated credits file --- credits.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/credits.txt b/credits.txt index f06377500a..6456e30a10 100644 --- a/credits.txt +++ b/credits.txt @@ -16,6 +16,7 @@ Alexander Nadeau (wareya) Alexander Olofsson (Ace) Artem Kotsynyak (greye) athile +Britt Mathis (galdor557) BrotherBrick Chris Robinson (KittyCat) Cory F. Cohen (cfcohen) From 2c70074dd745b083cdc99f38fff89e5e5f0776b3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 10 Apr 2013 20:25:03 +0200 Subject: [PATCH 0400/1537] Fix combinedAlpha --- files/materials/terrain.shader | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index de90a6cf61..58146118e9 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -227,7 +227,8 @@ #if !IS_FIRST_PASS -float combinedAlpha = 0.f; +// Opacity the previous passes should have, i.e. 1 - (opacity of this pass) +float previousAlpha = 1.f; #endif // Layer calculations @@ -252,7 +253,7 @@ float combinedAlpha = 0.f; #else albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); #endif - combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator); + previousAlpha *= 1.f-blendValues@shPropertyString(blendmap_component_@shIterator); #endif @shEndForeach @@ -344,7 +345,7 @@ float combinedAlpha = 0.f; #if IS_FIRST_PASS shOutputColour(0).a = 1; #else - shOutputColour(0).a = min(combinedAlpha, 1.f); + shOutputColour(0).a = 1.f-previousAlpha; #endif } From b98063bba03473d9dc0a7e0c3953069eb1a26ee9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 11 Apr 2013 18:02:44 +0200 Subject: [PATCH 0401/1537] Fix deleted pointer access (getPosition, getRotation) --- libs/openengine/bullet/physic.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index f71fa4320b..524f57c1c4 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -19,7 +19,7 @@ namespace Physic PhysicActor::PhysicActor(const std::string &name, const std::string &mesh, PhysicEngine *engine, const Ogre::Vector3 &position, const Ogre::Quaternion &rotation, float scale) : mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0) - , mBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) + , mBody(0), mRaycastingBody(0), onGround(false), collisionMode(true), mBoxRotation(0,0,0,0), verticalForce(0.0f) { // FIXME: Force player to start in no-collision mode for now, until he spawns at a proper door marker. if(name == "player") @@ -47,6 +47,7 @@ namespace Physic void PhysicActor::enableCollisions(bool collision) { + assert(mBody); if(collision && !collisionMode) mBody->translate(btVector3(0,0,-1000)); if(!collision && collisionMode) mBody->translate(btVector3(0,0,1000)); collisionMode = collision; @@ -55,6 +56,7 @@ namespace Physic void PhysicActor::setPosition(const Ogre::Vector3 &pos) { + assert(mBody); if(pos != getPosition()) { mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); @@ -64,6 +66,7 @@ namespace Physic void PhysicActor::setRotation(const Ogre::Quaternion &quat) { + assert(mBody); if(!quat.equals(getRotation(), Ogre::Radian(0))){ mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); mEngine->adjustRigidBody(mRaycastingBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); @@ -74,6 +77,7 @@ namespace Physic Ogre::Vector3 PhysicActor::getPosition() { + assert(mBody); btVector3 vec = mBody->getWorldTransform().getOrigin(); Ogre::Quaternion rotation = Ogre::Quaternion(mBody->getWorldTransform().getRotation().getW(), mBody->getWorldTransform().getRotation().getX(), mBody->getWorldTransform().getRotation().getY(), mBody->getWorldTransform().getRotation().getZ()); @@ -84,14 +88,18 @@ namespace Physic Ogre::Quaternion PhysicActor::getRotation() { + assert(mBody); btQuaternion quat = mBody->getWorldTransform().getRotation() * mBoxRotationInverse; return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } void PhysicActor::setScale(float scale){ //We only need to change the scaled box translation, box rotations remain the same. + assert(mBody); mBoxScaledTranslation = mBoxScaledTranslation / mBody->getCollisionShape()->getLocalScaling().getX(); mBoxScaledTranslation *= scale; + Ogre::Vector3 pos = getPosition(); + Ogre::Quaternion rot = getRotation(); if(mBody){ mEngine->dynamicsWorld->removeRigidBody(mBody); mEngine->dynamicsWorld->removeRigidBody(mRaycastingBody); @@ -99,8 +107,8 @@ namespace Physic delete mRaycastingBody; } //Create the newly scaled rigid body - mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation()); - mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, getPosition(), getRotation(), 0, 0, true); + mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot); + mRaycastingBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, pos, rot, 0, 0, true); mEngine->addRigidBody(mBody, false, mRaycastingBody); //Add rigid body to dynamics world, but do not add to object map } From 6934b20abd7c09ece9469f2be330512d91895982 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:57:58 +0100 Subject: [PATCH 0402/1537] actors are now updates every frame. This should not be the case, but this is a quickfix for AI. --- apps/openmw/mwmechanics/actors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 89671ee086..82e46ea463 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -210,7 +210,7 @@ namespace MWMechanics { mDuration += duration; - if (mDuration>=0.25) + //if (mDuration>=0.25) { float totalDuration = mDuration; mDuration = 0; From 0a187e56aa8331624163789059dee3ca85a25095 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 17:58:11 +0100 Subject: [PATCH 0403/1537] bugfix --- apps/openmw/mwmechanics/aitravel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 25efe8fff0..65d43749bc 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -80,9 +80,9 @@ namespace MWMechanics dest.mZ = mZ; ESM::Pathgrid::Point start; - dest.mX = pos.pos[0]; - dest.mY = pos.pos[1]; - dest.mZ = pos.pos[2]; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; mPathFinder.buildPath(start,dest,pathgrid,xCell,yCell); } From 905cff2a9456406f1be91ca311ab219980e9840c Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 11 Apr 2013 18:02:12 +0100 Subject: [PATCH 0404/1537] anonymous namespace --- apps/openmw/mwmechanics/aitravel.cpp | 15 +++++++++------ apps/openmw/mwmechanics/pathfinding.cpp | 8 +++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index 65d43749bc..13ae2a592e 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -13,6 +13,15 @@ #include #include "boost/tuple/tuple.hpp" +namespace +{ + float sgn(float a) + { + if(a>0) return 1.; + else return -1.; + } +} + namespace MWMechanics { @@ -26,12 +35,6 @@ namespace MWMechanics return new AiTravel(*this); } - static float sgn(float a) - { - if(a>0) return 1.; - else return -1.; - } - bool AiTravel::execute (const MWWorld::Ptr& actor) { const ESM::Pathgrid *pathgrid = diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 1d98674ef5..7c22e54701 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -4,10 +4,9 @@ #include "boost/tuple/tuple.hpp" #include "OgreMath.h" -namespace MWMechanics +namespace { - - //helpers functions + //helpers functions float distanceZCorrected(ESM::Pathgrid::Point point,float x,float y,float z) { return sqrt((point.mX - x)*(point.mX - x)+(point.mY - y)*(point.mY - y)+0.1*(point.mZ - z)*(point.mZ - z)); @@ -89,7 +88,10 @@ namespace MWMechanics const PathGridGraph & mGraph; PointID mGoal; }; +} +namespace MWMechanics +{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; From 23b477a9380c4c6a4f60a2b809ba17a6aa9dc884 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Apr 2013 04:36:28 +0200 Subject: [PATCH 0405/1537] Fix normal maps with spaces in filename not getting loaded --- components/nifogre/material.cpp | 5 ----- extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp | 9 +++++++++ files/materials/objects.mat | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/components/nifogre/material.cpp b/components/nifogre/material.cpp index 431b8219a9..55f064c555 100644 --- a/components/nifogre/material.cpp +++ b/components/nifogre/material.cpp @@ -333,11 +333,6 @@ Ogre::String NIFMaterialLoader::getMaterial(const Nif::ShapeData *shapedata, instance->setProperty("use_detail_map", sh::makeProperty(new sh::BooleanValue(true))); instance->setProperty("detailMapUVSet", sh::makeProperty(new sh::IntValue(texprop->textures[Nif::NiTexturingProperty::DetailTexture].uvSet))); } - if (!texName[Nif::NiTexturingProperty::BumpTexture].empty()) - { - // force automips on normal maps for now - instance->setProperty("normalMap", sh::makeProperty(texName[Nif::NiTexturingProperty::BumpTexture] + " 4")); - } for(int i = 0;i < 7;i++) { diff --git a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp index 4ec43fcaeb..f45e641557 100644 --- a/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp +++ b/extern/shiny/Platforms/Ogre/OgreMaterialSerializer.cpp @@ -2,6 +2,8 @@ #include +#include + namespace sh { void OgreMaterialSerializer::reset() @@ -44,6 +46,13 @@ namespace sh bool OgreMaterialSerializer::setTextureUnitProperty (const std::string& param, std::string value, Ogre::TextureUnitState* t) { + // quick access to automip setting, without having to use 'texture' which doesn't like spaces in filenames + if (param == "num_mipmaps") + { + t->setNumMipmaps(Ogre::StringConverter::parseInt(value)); + return true; + } + reset(); mScriptContext.section = Ogre::MSS_TEXTUREUNIT; diff --git a/files/materials/objects.mat b/files/materials/objects.mat index b9277914bd..8f8734d629 100644 --- a/files/materials/objects.mat +++ b/files/materials/objects.mat @@ -55,7 +55,9 @@ material openmw_objects_base texture_unit normalMap { - texture $normalMap + direct_texture $normalMap + // force automips here for now + num_mipmaps 4 } texture_unit emissiveMap From a1ece7de306091c5b7beb834c49b9e34809cae3a Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 12 Apr 2013 14:48:53 +0200 Subject: [PATCH 0406/1537] Bug #613: fixed assert in string literal access function --- components/interpreter/runtime.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/components/interpreter/runtime.cpp b/components/interpreter/runtime.cpp index dcf17d2558..8814ca7ffc 100644 --- a/components/interpreter/runtime.cpp +++ b/components/interpreter/runtime.cpp @@ -34,17 +34,20 @@ namespace Interpreter std::string Runtime::getStringLiteral (int index) const { - assert (index>=0 && index (mCode[3])); + assert (index>=0 && static_cast (mCode[3])>0); const char *literalBlock = reinterpret_cast (mCode + 4 + mCode[0] + mCode[1] + mCode[2]); + int offset = 0; + for (; index; --index) { - literalBlock += std::strlen (literalBlock) + 1; + offset += std::strlen (literalBlock+offset) + 1; + assert (offset/4 (mCode[3])); } - return literalBlock; + return literalBlock+offset; } void Runtime::configure (const Interpreter::Type_Code *code, int codeSize, Context& context) From 5b30677e41f26312a6eb844c65c6169967815471 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Apr 2013 14:37:16 -0700 Subject: [PATCH 0407/1537] Add the start of a custom gravity affector --- components/nifogre/ogrenifloader.cpp | 15 ++- libs/openengine/ogre/particles.cpp | 181 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 11 ++ libs/openengine/ogre/renderer.cpp | 4 + 4 files changed, 207 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 48893bf4a8..113fd3d162 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -366,10 +366,21 @@ class NIFObjectLoader if(e->recType == Nif::RC_NiParticleGrowFade) { const Nif::NiParticleGrowFade *gf = static_cast(e.getPtr()); + Ogre::ParticleAffector *affector = partsys->addAffector("GrowFade"); affector->setParameter("grow_time", Ogre::StringConverter::toString(gf->growTime)); affector->setParameter("fade_time", Ogre::StringConverter::toString(gf->fadeTime)); } + else if(e->recType == Nif::RC_NiGravity) + { + const Nif::NiGravity *gr = static_cast(e.getPtr()); + + Ogre::ParticleAffector *affector = partsys->addAffector("Gravity"); + affector->setParameter("force", Ogre::StringConverter::toString(gr->mForce)); + affector->setParameter("force_type", (gr->mType==0) ? "wind" : "point"); + affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); + affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); + } else if(e->recType == Nif::RC_NiParticleRotation) { // TODO: Implement (Ogre::RotationAffector?) @@ -378,10 +389,6 @@ class NIFObjectLoader { // TODO: Implement (Ogre::ColourInterpolatorAffector?) } - else if(e->recType == Nif::RC_NiGravity) - { - // TODO: Implement - } else warn("Unhandled particle modifier "+e->recName); e = e->extra; diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 3453b7f3d7..244ca0ec3b 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -144,3 +144,184 @@ Ogre::ParticleAffector *GrowFadeAffectorFactory::createAffector(Ogre::ParticleSy mAffectors.push_back(p); return p; } + + +class GravityAffector : public Ogre::ParticleAffector +{ + enum ForceType { + Type_Wind, + Type_Point + }; + +public: + /** Command object for force (see Ogre::ParamCommand).*/ + class CmdForce : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getForce()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setForce(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for force_type (see Ogre::ParamCommand).*/ + class CmdForceType : public Ogre::ParamCommand + { + static ForceType getTypeFromString(const Ogre::String &type) + { + if(type == "wind") + return Type_Wind; + if(type == "point") + return Type_Point; + OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type string: "+type, + "CmdForceType::getTypeFromString"); + } + + static Ogre::String getStringFromType(ForceType type) + { + switch(type) + { + case Type_Wind: return "wind"; + case Type_Point: return "point"; + } + OGRE_EXCEPT(Ogre::Exception::ERR_INVALIDPARAMS, "Invalid force type enum: "+Ogre::StringConverter::toString(type), + "CmdForceType::getStringFromType"); + } + + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return getStringFromType(self->getForceType()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setForceType(getTypeFromString(val)); + } + }; + + /** Command object for direction (see Ogre::ParamCommand).*/ + class CmdDirection : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getDirection()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setDirection(Ogre::StringConverter::parseVector3(val)); + } + }; + + /** Command object for position (see Ogre::ParamCommand).*/ + class CmdPosition : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const GravityAffector *self = static_cast(target); + return Ogre::StringConverter::toString(self->getPosition()); + } + void doSet(void *target, const Ogre::String &val) + { + GravityAffector *self = static_cast(target); + self->setPosition(Ogre::StringConverter::parseVector3(val)); + } + }; + + + /** Default constructor. */ + GravityAffector(Ogre::ParticleSystem *psys) + : ParticleAffector(psys) + , mForce(0.0f) + , mForceType(Type_Wind) + , mPosition(0.0f) + , mDirection(0.0f) + { + mType = "Gravity"; + + // Init parameters + if(createParamDictionary("GravityAffector")) + { + Ogre::ParamDictionary *dict = getParamDictionary(); + + Ogre::String force_title("force"); + Ogre::String force_descr("Amount of force applied to particles."); + Ogre::String force_type_title("force_type"); + Ogre::String force_type_descr("Type of force applied to particles (point or wind)."); + Ogre::String direction_title("direction"); + Ogre::String direction_descr("Direction of wind forces."); + Ogre::String position_title("position"); + Ogre::String position_descr("Position of point forces."); + + dict->addParameter(Ogre::ParameterDef(force_title, force_descr, Ogre::PT_REAL), &msForceCmd); + dict->addParameter(Ogre::ParameterDef(force_type_title, force_type_descr, Ogre::PT_STRING), &msForceTypeCmd); + dict->addParameter(Ogre::ParameterDef(direction_title, direction_descr, Ogre::PT_VECTOR3), &msDirectionCmd); + dict->addParameter(Ogre::ParameterDef(position_title, position_descr, Ogre::PT_VECTOR3), &msPositionCmd); + } + } + + /** See Ogre::ParticleAffector. */ + void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + } + } + + void setForce(Ogre::Real force) + { mForce = force; } + Ogre::Real getForce() const + { return mForce; } + + void setForceType(ForceType type) + { mForceType = type; } + ForceType getForceType() const + { return mForceType; } + + void setDirection(const Ogre::Vector3 &dir) + { mDirection = dir; } + const Ogre::Vector3 &getDirection() const + { return mDirection; } + + void setPosition(const Ogre::Vector3 &pos) + { mPosition = pos; } + const Ogre::Vector3 &getPosition() const + { return mPosition; } + + static CmdForce msForceCmd; + static CmdForceType msForceTypeCmd; + static CmdDirection msDirectionCmd; + static CmdPosition msPositionCmd; + +protected: + float mForce; + + ForceType mForceType; + + Ogre::Vector3 mPosition; + Ogre::Vector3 mDirection; +}; +GravityAffector::CmdForce GravityAffector::msForceCmd; +GravityAffector::CmdForceType GravityAffector::msForceTypeCmd; +GravityAffector::CmdDirection GravityAffector::msDirectionCmd; +GravityAffector::CmdPosition GravityAffector::msPositionCmd; + +Ogre::ParticleAffector *GravityAffectorFactory::createAffector(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleAffector *p = new GravityAffector(psys); + mAffectors.push_back(p); + return p; +} diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index d466bb0308..0d88a348e3 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -14,4 +14,15 @@ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); }; +/** Factory class for GravityAffector. */ +class GravityAffectorFactory : public Ogre::ParticleAffectorFactory +{ + /** See Ogre::ParticleAffectorFactory */ + Ogre::String getName() const + { return "Gravity"; } + + /** See Ogre::ParticleAffectorFactory */ + Ogre::ParticleAffector *createAffector(Ogre::ParticleSystem *psys); +}; + #endif /* OENGINE_OGRE_PARTICLES_H */ diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index c9e91968f5..fcc4961b50 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -211,6 +211,10 @@ void OgreRenderer::configure(const std::string &logPath, Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); mAffectorFactories.push_back(affector); + affector = OGRE_NEW GravityAffectorFactory(); + Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); + mAffectorFactories.push_back(affector); + RenderSystem* rs = mRoot->getRenderSystemByName(renderSystem); if (rs == 0) From 86bac7aa9201ac54b71de4d76b150d1a95695daf Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 12 Apr 2013 23:40:30 +0200 Subject: [PATCH 0408/1537] Fix wrong BSA group name typo --- apps/openmw/engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 17610e479f..118932ade6 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -176,7 +176,7 @@ void OMW::Engine::loadBSA() if (mFileCollections.doesExist(*archive)) { // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(dataDirs.size()-i); + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); From 2eb9395661d84bb56603472564b79a0d9a054222 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Apr 2013 00:05:31 +0200 Subject: [PATCH 0409/1537] Do some padding with zeros on the resource group name to avoid priority problems with more than 10 resource groups. --- apps/openmw/engine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 118932ade6..69e3cdc534 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -161,7 +161,7 @@ void OMW::Engine::loadBSA() for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) { // Last data dir has the highest priority - std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i); + std::string groupName = "Data" + Ogre::StringConverter::toString(dataDirs.size()-i, 8, '0'); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); std::string dataDirectory = iter->string(); @@ -176,7 +176,7 @@ void OMW::Engine::loadBSA() if (mFileCollections.doesExist(*archive)) { // Last BSA has the highest priority - std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i); + std::string groupName = "DataBSA" + Ogre::StringConverter::toString(mArchives.size()-i, 8, '0'); Ogre::ResourceGroupManager::getSingleton ().createResourceGroup (groupName); From d50150ad715d278b42ec2201a0ad7728649db748 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 13 Apr 2013 00:13:56 +0200 Subject: [PATCH 0410/1537] Scale adjustment factor should not be written back to cellref scale --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2fc..e70aedd552 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -801,8 +801,8 @@ namespace MWWorld void World::scaleObject (const Ptr& ptr, float scale) { - MWWorld::Class::get(ptr).adjustScale(ptr,scale); ptr.getCellRef().mScale = scale; + MWWorld::Class::get(ptr).adjustScale(ptr,scale); if(ptr.getRefData().getBaseNode() == 0) return; From 9cc97b195c1732bd784833452c49baee829b2c8a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 13:03:45 -0700 Subject: [PATCH 0411/1537] Implement Gravity particle affector effects --- libs/openengine/ogre/particles.cpp | 34 +++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 244ca0ec3b..61ebddc562 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -274,10 +274,14 @@ public: /** See Ogre::ParticleAffector. */ void _affectParticles(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) { - Ogre::ParticleIterator pi = psys->_getIterator(); - while (!pi.end()) + switch(mForceType) { - Ogre::Particle *p = pi.getNext(); + case Type_Wind: + applyWindForce(psys, timeElapsed); + break; + case Type_Point: + applyPointForce(psys, timeElapsed); + break; } } @@ -307,6 +311,30 @@ public: static CmdPosition msPositionCmd; protected: + void applyWindForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + const Ogre::Vector3 vec = mDirection * mForce * timeElapsed; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + p->direction += vec; + } + } + + void applyPointForce(Ogre::ParticleSystem *psys, Ogre::Real timeElapsed) + { + const Ogre::Real force = mForce * timeElapsed; + Ogre::ParticleIterator pi = psys->_getIterator(); + while (!pi.end()) + { + Ogre::Particle *p = pi.getNext(); + const Ogre::Vector3 vec = (p->position - mPosition).normalisedCopy() * force; + p->direction += vec; + } + } + + float mForce; ForceType mForceType; From 07c24e038212d6b1b3eb52838f9af690b4fa4c00 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 13:13:09 -0700 Subject: [PATCH 0412/1537] Don't create entities and particles when only the skeleton base is needed --- components/nifogre/ogrenifloader.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 113fd3d162..4e6d3b3c45 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -468,7 +468,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags=0) + ObjectList &objectlist, int flags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -585,8 +585,8 @@ class NIFObjectLoader } } - if(node->recType == Nif::RC_NiAutoNormalParticles || - node->recType == Nif::RC_NiRotatingParticles) + if((node->recType == Nif::RC_NiAutoNormalParticles || + node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); if(partsys != NULL) @@ -614,8 +614,7 @@ class NIFObjectLoader { /* This creates an empty mesh to which a skeleton gets attached. This * is to ensure we have an entity with a skeleton instance, even if all - * other meshes are hidden or entities attached to a specific node - * instead of skinned. */ + * other entities are attached to bones and not skinned. */ Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); if(meshMgr.getByName(name).isNull()) NIFMeshLoader::createMesh(name, name, group, ~(size_t)0); @@ -625,7 +624,7 @@ class NIFObjectLoader } public: - static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group) + static void load(Ogre::SceneManager *sceneMgr, ObjectList &objectlist, const std::string &name, const std::string &group, int flags=0) { Nif::NIFFile::ptr nif = Nif::NIFFile::create(name); if(nif->numRoots() < 1) @@ -651,7 +650,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist); + createObjects(name, group, sceneMgr, node, objectlist, flags); } }; @@ -739,7 +738,7 @@ ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string na ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group); + NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); return objectlist; } From 7191f6ed2a7f500b1d51275d8ece011ed9590f8c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 14:36:24 -0700 Subject: [PATCH 0413/1537] Start a Nif-style particle emitter Not complete yet (doesn't handle the vertical or horizontal direction/angle), and should probably be renamed. --- components/nifogre/ogrenifloader.cpp | 5 +- libs/openengine/ogre/particles.cpp | 217 +++++++++++++++++++++++++++ libs/openengine/ogre/particles.hpp | 13 ++ libs/openengine/ogre/renderer.cpp | 12 ++ libs/openengine/ogre/renderer.hpp | 2 + 5 files changed, 248 insertions(+), 1 deletion(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 4e6d3b3c45..d546ca2712 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -351,7 +351,7 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { - Ogre::ParticleEmitter *emitter = partsys->addEmitter("Point"); + Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, @@ -359,6 +359,9 @@ class NIFObjectLoader emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 61ebddc562..a6bc78d5fb 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -2,9 +2,226 @@ #include #include +#include #include #include +/* FIXME: "Nif" isn't really an appropriate emitter name. */ +class NifEmitter : public Ogre::ParticleEmitter +{ +public: + /** Command object for the emitter width (see Ogre::ParamCommand).*/ + class CmdWidth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getWidth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setWidth(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter height (see Ogre::ParamCommand).*/ + class CmdHeight : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getHeight()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setHeight(Ogre::StringConverter::parseReal(val)); + } + }; + + /** Command object for the emitter depth (see Ogre::ParamCommand).*/ + class CmdDepth : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + return Ogre::StringConverter::toString(static_cast(target)->getDepth()); + } + void doSet(void *target, const Ogre::String &val) + { + static_cast(target)->setDepth(Ogre::StringConverter::parseReal(val)); + } + }; + + + NifEmitter(Ogre::ParticleSystem *psys) + : Ogre::ParticleEmitter(psys) + { + initDefaults("Nif"); + } + + /** See Ogre::ParticleEmitter. */ + unsigned short _getEmissionCount(Ogre::Real timeElapsed) + { + // Use basic constant emission + return genConstantEmissionCount(timeElapsed); + } + + /** See Ogre::ParticleEmitter. */ + void _initParticle(Ogre::Particle *particle) + { + Ogre::Vector3 xOff, yOff, zOff; + + // Call superclass + ParticleEmitter::_initParticle(particle); + + xOff = Ogre::Math::SymmetricRandom() * mXRange; + yOff = Ogre::Math::SymmetricRandom() * mYRange; + zOff = Ogre::Math::SymmetricRandom() * mZRange; + + particle->position = mPosition + xOff + yOff + zOff; + + // Generate complex data by reference + genEmissionColour(particle->colour); + genEmissionDirection(particle->direction); + genEmissionVelocity(particle->direction); + + // Generate simpler data + particle->timeToLive = particle->totalTimeToLive = genEmissionTTL(); + } + + /** Overloaded to update the trans. matrix */ + void setDirection(const Ogre::Vector3 &dir) + { + ParticleEmitter::setDirection(dir); + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param + size Vector describing the size of the area. The area extends + around the center point by half the x, y and z components of + this vector. The box is aligned such that it's local Z axis points + along it's direction (see setDirection) + */ + void setSize(const Ogre::Vector3 &size) + { + mSize = size; + genAreaAxes(); + } + + /** Sets the size of the area from which particles are emitted. + @param x,y,z + Individual axis lengths describing the size of the area. The area + extends around the center point by half the x, y and z components + of this vector. The box is aligned such that it's local Z axis + points along it's direction (see setDirection) + */ + void setSize(Ogre::Real x, Ogre::Real y, Ogre::Real z) + { + mSize.x = x; + mSize.y = y; + mSize.z = z; + genAreaAxes(); + } + + /** Sets the width (local x size) of the emitter. */ + void setWidth(Ogre::Real width) + { + mSize.x = width; + genAreaAxes(); + } + /** Gets the width (local x size) of the emitter. */ + Ogre::Real getWidth(void) const + { return mSize.x; } + /** Sets the height (local y size) of the emitter. */ + void setHeight(Ogre::Real height) + { + mSize.y = height; + genAreaAxes(); + } + /** Gets the height (local y size) of the emitter. */ + Ogre::Real getHeight(void) const + { return mSize.y; } + /** Sets the depth (local y size) of the emitter. */ + void setDepth(Ogre::Real depth) + { + mSize.z = depth; + genAreaAxes(); + } + /** Gets the depth (local y size) of the emitter. */ + Ogre::Real getDepth(void) const + { return mSize.z; } + +protected: + /// Size of the area + Ogre::Vector3 mSize; + + /// Local axes, not normalised, their magnitude reflects area size + Ogre::Vector3 mXRange, mYRange, mZRange; + + /// Internal method for generating the area axes + void genAreaAxes(void) + { + Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); + + mXRange = mLeft * (mSize.x * 0.5f); + mYRange = mUp * (mSize.y * 0.5f); + mZRange = mDirection * (mSize.z * 0.5f); + } + + /** Internal for initializing some defaults and parameters + @return True if custom parameters need initialising + */ + bool initDefaults(const Ogre::String &t) + { + // Defaults + mDirection = Ogre::Vector3::UNIT_Z; + mUp = Ogre::Vector3::UNIT_Y; + setSize(100.0f, 100.0f, 100.0f); + mType = t; + + // Set up parameters + if(createParamDictionary(mType + "Emitter")) + { + addBaseParameters(); + Ogre::ParamDictionary *dict = getParamDictionary(); + + // Custom params + dict->addParameter(Ogre::ParameterDef("width", + "Width of the shape in world coordinates.", + Ogre::PT_REAL), + &msWidthCmd); + dict->addParameter(Ogre::ParameterDef("height", + "Height of the shape in world coordinates.", + Ogre::PT_REAL), + &msHeightCmd); + dict->addParameter(Ogre::ParameterDef("depth", + "Depth of the shape in world coordinates.", + Ogre::PT_REAL), + &msDepthCmd); + + return true; + } + return false; + } + + /// Command objects + static CmdWidth msWidthCmd; + static CmdHeight msHeightCmd; + static CmdDepth msDepthCmd; +}; +NifEmitter::CmdWidth NifEmitter::msWidthCmd; +NifEmitter::CmdHeight NifEmitter::msHeightCmd; +NifEmitter::CmdDepth NifEmitter::msDepthCmd; + +Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) +{ + Ogre::ParticleEmitter *emit = OGRE_NEW NifEmitter(psys); + mEmitters.push_back(emit); + return emit; +} + + class GrowFadeAffector : public Ogre::ParticleAffector { public: diff --git a/libs/openengine/ogre/particles.hpp b/libs/openengine/ogre/particles.hpp index 0d88a348e3..e1f3fd282c 100644 --- a/libs/openengine/ogre/particles.hpp +++ b/libs/openengine/ogre/particles.hpp @@ -1,8 +1,21 @@ #ifndef OENGINE_OGRE_PARTICLES_H #define OENGINE_OGRE_PARTICLES_H +#include #include +/** Factory class for NifEmitter. */ +class NifEmitterFactory : public Ogre::ParticleEmitterFactory +{ +public: + /** See ParticleEmitterFactory */ + Ogre::String getName() const + { return "Nif"; } + + /** See ParticleEmitterFactory */ + Ogre::ParticleEmitter* createEmitter(Ogre::ParticleSystem *psys); +}; + /** Factory class for GrowFadeAffector. */ class GrowFadeAffectorFactory : public Ogre::ParticleAffectorFactory { diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index fcc4961b50..7be7137969 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -110,6 +110,11 @@ void OgreRenderer::loadPlugins() void OgreRenderer::unloadPlugins() { + std::vector::iterator ei; + for(ei = mEmitterFactories.begin();ei != mEmitterFactories.end();ei++) + OGRE_DELETE (*ei); + mEmitterFactories.clear(); + std::vector::iterator ai; for(ai = mAffectorFactories.begin();ai != mAffectorFactories.end();ai++) OGRE_DELETE (*ai); @@ -206,6 +211,13 @@ void OgreRenderer::configure(const std::string &logPath, Files::loadOgrePlugin(pluginDir, "Plugin_CgProgramManager", *mRoot); Files::loadOgrePlugin(pluginDir, "Plugin_ParticleFX", *mRoot); + + Ogre::ParticleEmitterFactory *emitter; + emitter = OGRE_NEW NifEmitterFactory(); + Ogre::ParticleSystemManager::getSingleton().addEmitterFactory(emitter); + mEmitterFactories.push_back(emitter); + + Ogre::ParticleAffectorFactory *affector; affector = OGRE_NEW GrowFadeAffectorFactory(); Ogre::ParticleSystemManager::getSingleton().addAffectorFactory(affector); diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index ea46f5ae62..962ae4f2ec 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -40,6 +40,7 @@ namespace Ogre class SceneManager; class Camera; class Viewport; + class ParticleEmitterFactory; class ParticleAffectorFactory; } @@ -95,6 +96,7 @@ namespace OEngine Ogre::D3D9Plugin* mD3D9Plugin; #endif Fader* mFader; + std::vector mEmitterFactories; std::vector mAffectorFactories; bool logging; From dd981077b955e8be6123c05765467112b61d5cdc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:16:57 -0700 Subject: [PATCH 0414/1537] Handle the vertical and horizontal parameters of Nif particles Note that 'horizontal' is mapped to rotate around the Z axis, not Y. The Nif particle parameters seem to be set up to expect a normal OpenGL (Direct3D?) orientation, rather than the 90-degree pitch offset of the game. --- components/nifogre/ogrenifloader.cpp | 10 ++- libs/openengine/ogre/particles.cpp | 125 ++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 6 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index d546ca2712..78b60d7121 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -352,16 +352,18 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setDirection(Ogre::Vector3(0.0f, 0.0f, std::cos(partctrl->verticalDir))); - emitter->setAngle(Ogre::Radian(partctrl->verticalAngle)); emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, partctrl->velocity+partctrl->velocityRandom); emitter->setEmissionRate(partctrl->emitRate); emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, partctrl->lifetime+partctrl->lifetimeRandom); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); - emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); - emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); + emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); + emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); + emitter->setParameter("vertical_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalDir).valueDegrees())); + emitter->setParameter("vertical_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->verticalAngle).valueDegrees())); + emitter->setParameter("horizontal_direction", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalDir).valueDegrees())); + emitter->setParameter("horizontal_angle", Ogre::StringConverter::toString(Ogre::Radian(partctrl->horizontalAngle).valueDegrees())); Nif::ExtraPtr e = partctrl->extra; while(!e.empty()) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index a6bc78d5fb..5cb92bf0f3 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -52,6 +52,70 @@ public: } }; + /** Command object for the emitter vertical_direction (see Ogre::ParamCommand).*/ + class CmdVerticalDir : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getVerticalDirection().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setVerticalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter vertical_angle (see Ogre::ParamCommand).*/ + class CmdVerticalAngle : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getVerticalAngle().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setVerticalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter horizontal_direction (see Ogre::ParamCommand).*/ + class CmdHorizontalDir : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getHorizontalDirection().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setHorizontalDirection(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + + /** Command object for the emitter horizontal_angle (see Ogre::ParamCommand).*/ + class CmdHorizontalAngle : public Ogre::ParamCommand + { + public: + Ogre::String doGet(const void *target) const + { + const NifEmitter *self = static_cast(target); + return Ogre::StringConverter::toString(self->getHorizontalAngle().valueDegrees()); + } + void doSet(void *target, const Ogre::String &val) + { + NifEmitter *self = static_cast(target); + self->setHorizontalAngle(Ogre::Degree(Ogre::StringConverter::parseReal(val))); + } + }; + NifEmitter(Ogre::ParticleSystem *psys) : Ogre::ParticleEmitter(psys) @@ -82,7 +146,14 @@ public: // Generate complex data by reference genEmissionColour(particle->colour); - genEmissionDirection(particle->direction); + + // NOTE: We do not use mDirection/mAngle for the initial direction. + Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); + Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); + particle->direction = (Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X) * + Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z)) * + Ogre::Vector3::UNIT_Z; + genEmissionVelocity(particle->direction); // Generate simpler data @@ -152,10 +223,36 @@ public: Ogre::Real getDepth(void) const { return mSize.z; } + void setVerticalDirection(Ogre::Radian vdir) + { mVerticalDir = vdir; } + Ogre::Radian getVerticalDirection(void) const + { return mVerticalDir; } + + void setVerticalAngle(Ogre::Radian vangle) + { mVerticalAngle = vangle; } + Ogre::Radian getVerticalAngle(void) const + { return mVerticalAngle; } + + void setHorizontalDirection(Ogre::Radian hdir) + { mHorizontalDir = hdir; } + Ogre::Radian getHorizontalDirection(void) const + { return mHorizontalDir; } + + void setHorizontalAngle(Ogre::Radian hangle) + { mHorizontalAngle = hangle; } + Ogre::Radian getHorizontalAngle(void) const + { return mHorizontalAngle; } + + protected: /// Size of the area Ogre::Vector3 mSize; + Ogre::Radian mVerticalDir; + Ogre::Radian mVerticalAngle; + Ogre::Radian mHorizontalDir; + Ogre::Radian mHorizontalAngle; + /// Local axes, not normalised, their magnitude reflects area size Ogre::Vector3 mXRange, mYRange, mZRange; @@ -163,7 +260,6 @@ protected: void genAreaAxes(void) { Ogre::Vector3 mLeft = mUp.crossProduct(mDirection); - mXRange = mLeft * (mSize.x * 0.5f); mYRange = mUp * (mSize.y * 0.5f); mZRange = mDirection * (mSize.z * 0.5f); @@ -200,6 +296,23 @@ protected: Ogre::PT_REAL), &msDepthCmd); + dict->addParameter(Ogre::ParameterDef("vertical_direction", + "Vertical direction of emitted particles (in degrees).", + Ogre::PT_REAL), + &msVerticalDirCmd); + dict->addParameter(Ogre::ParameterDef("vertical_angle", + "Vertical direction variance of emitted particles (in degrees).", + Ogre::PT_REAL), + &msVerticalAngleCmd); + dict->addParameter(Ogre::ParameterDef("horizontal_direction", + "Horizontal direction of emitted particles (in degrees).", + Ogre::PT_REAL), + &msHorizontalDirCmd); + dict->addParameter(Ogre::ParameterDef("horizontal_angle", + "Horizontal direction variance of emitted particles (in degrees).", + Ogre::PT_REAL), + &msHorizontalAngleCmd); + return true; } return false; @@ -209,10 +322,18 @@ protected: static CmdWidth msWidthCmd; static CmdHeight msHeightCmd; static CmdDepth msDepthCmd; + static CmdVerticalDir msVerticalDirCmd; + static CmdVerticalAngle msVerticalAngleCmd; + static CmdHorizontalDir msHorizontalDirCmd; + static CmdHorizontalAngle msHorizontalAngleCmd; }; NifEmitter::CmdWidth NifEmitter::msWidthCmd; NifEmitter::CmdHeight NifEmitter::msHeightCmd; NifEmitter::CmdDepth NifEmitter::msDepthCmd; +NifEmitter::CmdVerticalDir NifEmitter::msVerticalDirCmd; +NifEmitter::CmdVerticalAngle NifEmitter::msVerticalAngleCmd; +NifEmitter::CmdHorizontalDir NifEmitter::msHorizontalDirCmd; +NifEmitter::CmdHorizontalAngle NifEmitter::msHorizontalAngleCmd; Ogre::ParticleEmitter* NifEmitterFactory::createEmitter(Ogre::ParticleSystem *psys) { From 80a4345787d71d60e7d202bd1898ce2b5e4694ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:26:34 -0700 Subject: [PATCH 0415/1537] Keep particles in local space --- components/nifogre/ogrenifloader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 78b60d7121..40730a586f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -436,6 +436,9 @@ class NIFObjectLoader particledata->particleRadius*2.0f); partsys->setCullIndividually(false); partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); Nif::ControllerPtr ctrl = partnode->controller; while(!ctrl.empty()) From 0b363ba36e41e28bf3193e5774533218e68e6fa6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 16:42:32 -0700 Subject: [PATCH 0416/1537] Handle NiParticleColorModifier with Ogre's ColourInterpolator Note that Ogre's ColourInterpolator has a maximum of six color stages. This seems to be fine so far, but if we want anything better, we'll need a custom affector for it. --- components/nifogre/ogrenifloader.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 40730a586f..a26f431311 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -386,14 +386,30 @@ class NIFObjectLoader affector->setParameter("direction", Ogre::StringConverter::toString(gr->mDirection)); affector->setParameter("position", Ogre::StringConverter::toString(gr->mPosition)); } + else if(e->recType == Nif::RC_NiParticleColorModifier) + { + const Nif::NiParticleColorModifier *cl = static_cast(e.getPtr()); + const Nif::NiColorData *clrdata = cl->data.getPtr(); + + Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); + size_t num_colors = std::min(6, clrdata->mKeyList.mKeys.size()); + for(size_t i = 0;i < num_colors;i++) + { + Ogre::ColourValue color; + color.r = clrdata->mKeyList.mKeys[i].mValue[0]; + color.g = clrdata->mKeyList.mKeys[i].mValue[1]; + color.b = clrdata->mKeyList.mKeys[i].mValue[2]; + color.a = clrdata->mKeyList.mKeys[i].mValue[3]; + affector->setParameter("colour"+Ogre::StringConverter::toString(i), + Ogre::StringConverter::toString(color)); + affector->setParameter("time"+Ogre::StringConverter::toString(i), + Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime)); + } + } else if(e->recType == Nif::RC_NiParticleRotation) { // TODO: Implement (Ogre::RotationAffector?) } - else if(e->recType == Nif::RC_NiParticleColorModifier) - { - // TODO: Implement (Ogre::ColourInterpolatorAffector?) - } else warn("Unhandled particle modifier "+e->recName); e = e->extra; From 254c6840d817abd9b8b2c7428a8c1f359316ec0f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 18:22:30 -0700 Subject: [PATCH 0417/1537] Fix particle direction --- libs/openengine/ogre/particles.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/openengine/ogre/particles.cpp b/libs/openengine/ogre/particles.cpp index 5cb92bf0f3..707bd75e08 100644 --- a/libs/openengine/ogre/particles.cpp +++ b/libs/openengine/ogre/particles.cpp @@ -148,10 +148,10 @@ public: genEmissionColour(particle->colour); // NOTE: We do not use mDirection/mAngle for the initial direction. - Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); Ogre::Radian hdir = mHorizontalDir + mHorizontalAngle*Ogre::Math::SymmetricRandom(); - particle->direction = (Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X) * - Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z)) * + Ogre::Radian vdir = mVerticalDir + mVerticalAngle*Ogre::Math::SymmetricRandom(); + particle->direction = (Ogre::Quaternion(hdir, Ogre::Vector3::UNIT_Z) * + Ogre::Quaternion(vdir, Ogre::Vector3::UNIT_X)) * Ogre::Vector3::UNIT_Z; genEmissionVelocity(particle->direction); From acb1b5f0025a01e827a18159aeef9a95cbbebdf4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Apr 2013 22:54:32 -0700 Subject: [PATCH 0418/1537] Try to handle NiBSAnimationNode This is still incomplete guess work. Currently it seems as though flag 0x20 specifies whether the controllers auto-play (if on), rather than follow the object's animation time. --- components/nifogre/ogrenifloader.cpp | 26 ++++++++++++++++---------- components/nifogre/skeleton.cpp | 1 + 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f431311..ec53b79aa5 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -492,7 +492,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags) + ObjectList &objectlist, int flags, int animflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -503,7 +503,10 @@ class NIFObjectLoader if (node->name.find("marker") != std::string::npos) return; - flags |= node->flags; + if(node->recType == Nif::RC_NiBSAnimationNode) + animflags |= node->flags; + else + flags |= node->flags; Nif::ExtraPtr e = node->extra; while(!e.empty()) @@ -539,9 +542,10 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -552,9 +556,10 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval; /* Filled in later */ + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, false)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -599,9 +604,10 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval(Ogre::ControllerManager::getSingleton().getFrameTimeSource()); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, true)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -627,7 +633,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); } } } @@ -674,7 +680,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef03..28df4894db 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -164,6 +164,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, if(!(node->recType == Nif::RC_NiNode || /* Nothing special; children traversed below */ node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ + node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From f4695ec4ac487812b2b9120e1ebd90726ba9fd58 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 00:06:40 -0700 Subject: [PATCH 0419/1537] Cleanup NIFObjectLoader some --- components/nifogre/ogrenifloader.cpp | 213 +++++++++++++-------------- 1 file changed, 106 insertions(+), 107 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index ec53b79aa5..631d397283 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -331,9 +331,9 @@ public: -/** Manual resource loader for NIF objects (meshes, particle systems, etc). - * This is the main class responsible for translating the internal NIF - * structures into something Ogre can use. +/** Object creator for NIFs. This is the main class responsible for creating + * "live" Ogre objects (entities, particle systems, controllers, etc) from + * their NIF equivalents. */ class NIFObjectLoader { @@ -349,6 +349,57 @@ class NIFObjectLoader } + static void createEntity(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *node, int flags, int animflags) + { + const Nif::NiTriShape *shape = static_cast(node); + + std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); + if(shape->name.length() > 0) + fullname += "@shape="+shape->name; + Misc::StringUtils::toLower(fullname); + + Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); + if(meshMgr.getByName(fullname).isNull()) + NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); + + Ogre::Entity *entity = sceneMgr->createEntity(fullname); + entity->setVisible(!(flags&0x01)); + + objectlist.mEntities.push_back(entity); + if(objectlist.mSkelBase) + { + if(entity->hasSkeleton()) + entity->shareSkeletonInstanceWith(objectlist.mSkelBase); + else + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); + } + } + + Nif::ControllerPtr ctrl = node->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiUVController) + { + const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); + + const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); + Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + ctrl = ctrl->next; + } + } + + static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); @@ -416,9 +467,9 @@ class NIFObjectLoader } } - static Ogre::ParticleSystem *createParticleSystem(const std::string &name, const std::string &group, - Ogre::SceneManager *sceneMgr, Ogre::Entity *entitybase, - const Nif::Node *partnode) + static void createParticleSystem(const std::string &name, const std::string &group, + Ogre::SceneManager *sceneMgr, ObjectList &objectlist, + const Nif::Node *partnode, int flags, int animflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -426,67 +477,63 @@ class NIFObjectLoader else if(partnode->recType == Nif::RC_NiRotatingParticles) particledata = static_cast(partnode)->data.getPtr(); + std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); + if(partnode->name.length() > 0) + fullname += "@type="+partnode->name; + Misc::StringUtils::toLower(fullname); + Ogre::ParticleSystem *partsys = sceneMgr->createParticleSystem(); - try { - std::string fullname = name+"@index="+Ogre::StringConverter::toString(partnode->recIndex); - if(partnode->name.length() > 0) - fullname += "@type="+partnode->name; - Misc::StringUtils::toLower(fullname); - const Nif::NiTexturingProperty *texprop = NULL; - const Nif::NiMaterialProperty *matprop = NULL; - const Nif::NiAlphaProperty *alphaprop = NULL; - const Nif::NiVertexColorProperty *vertprop = NULL; - const Nif::NiZBufferProperty *zprop = NULL; - const Nif::NiSpecularProperty *specprop = NULL; - const Nif::NiWireframeProperty *wireprop = NULL; - bool needTangents = false; + const Nif::NiTexturingProperty *texprop = NULL; + const Nif::NiMaterialProperty *matprop = NULL; + const Nif::NiAlphaProperty *alphaprop = NULL; + const Nif::NiVertexColorProperty *vertprop = NULL; + const Nif::NiZBufferProperty *zprop = NULL; + const Nif::NiSpecularProperty *specprop = NULL; + const Nif::NiWireframeProperty *wireprop = NULL; + bool needTangents = false; - partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); - partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, - texprop, matprop, alphaprop, - vertprop, zprop, specprop, - wireprop, needTangents)); + partnode->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); + partsys->setMaterialName(NIFMaterialLoader::getMaterial(particledata, fullname, group, + texprop, matprop, alphaprop, + vertprop, zprop, specprop, + wireprop, needTangents)); - partsys->setDefaultDimensions(particledata->particleRadius*2.0f, - particledata->particleRadius*2.0f); - partsys->setCullIndividually(false); - partsys->setParticleQuota(particledata->numParticles); - // TODO: There is probably a field or flag to specify this, as some - // particle effects have it and some don't. - partsys->setKeepParticlesInLocalSpace(true); + partsys->setDefaultDimensions(particledata->particleRadius*2.0f, + particledata->particleRadius*2.0f); + partsys->setCullIndividually(false); + partsys->setParticleQuota(particledata->numParticles); + // TODO: There is probably a field or flag to specify this, as some + // particle effects have it and some don't. + partsys->setKeepParticlesInLocalSpace(true); - Nif::ControllerPtr ctrl = partnode->controller; - while(!ctrl.empty()) + Nif::ControllerPtr ctrl = partnode->controller; + while(!ctrl.empty()) + { + if(ctrl->recType == Nif::RC_NiParticleSystemController) { - if(ctrl->recType == Nif::RC_NiParticleSystemController) + const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); + + createParticleEmitterAffectors(partsys, partctrl); + if(!partctrl->emitter.empty() && !partsys->isAttached()) { - const Nif::NiParticleSystemController *partctrl = static_cast(ctrl.getPtr()); - - createParticleEmitterAffectors(partsys, partctrl); - if(!partctrl->emitter.empty() && !partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); - } + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partctrl->emitter->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - ctrl = ctrl->next; - } - - if(!partsys->isAttached()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); - Ogre::Bone *trgtbone = entitybase->getSkeleton()->getBone(trgtid); - entitybase->attachObjectToBone(trgtbone->getName(), partsys); } + ctrl = ctrl->next; } - catch(std::exception &e) { - std::cerr<< "Particles exception: "<destroyParticleSystem(partsys); - partsys = NULL; - }; - return partsys; + + if(!partsys->isAttached()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, partnode->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); + } + + partsys->setVisible(!(flags&0x01)); + objectlist.mParticles.push_back(partsys); } @@ -569,61 +616,13 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { - const Nif::NiTriShape *shape = static_cast(node); - - std::string fullname = name+"@index="+Ogre::StringConverter::toString(shape->recIndex); - if(shape->name.length() > 0) - fullname += "@shape="+shape->name; - Misc::StringUtils::toLower(fullname); - - Ogre::MeshManager &meshMgr = Ogre::MeshManager::getSingleton(); - if(meshMgr.getByName(fullname).isNull()) - NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); - - Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); - - objectlist.mEntities.push_back(entity); - if(objectlist.mSkelBase) - { - if(entity->hasSkeleton()) - entity->shareSkeletonInstanceWith(objectlist.mSkelBase); - else - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, shape->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), entity); - } - } - - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiUVController) - { - const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); - - const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - ctrl = ctrl->next; - } + createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); } if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - Ogre::ParticleSystem *partsys = createParticleSystem(name, group, sceneMgr, objectlist.mSkelBase, node); - if(partsys != NULL) - { - partsys->setVisible(!(flags&0x01)); - objectlist.mParticles.push_back(partsys); - } + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); } const Nif::NiNode *ninode = dynamic_cast(node); From 03af0a8ac972ca22a4f918523cd1be2ff28579a4 Mon Sep 17 00:00:00 2001 From: Marek Kochanowicz Date: Sun, 14 Apr 2013 10:02:48 +0200 Subject: [PATCH 0420/1537] Adding more icons from nomadic1, replacing older with recently redoned. --- files/opencs/raster/apparatus.png | Bin 1580 -> 1440 bytes files/opencs/raster/armor.png | Bin 1908 -> 1641 bytes files/opencs/raster/clothing.png | Bin 0 -> 1377 bytes files/opencs/raster/container.png | Bin 1570 -> 1526 bytes files/opencs/raster/creature.png | Bin 2506 -> 2297 bytes files/opencs/raster/door.png | Bin 1715 -> 1627 bytes files/opencs/raster/leveled-creature.png | Bin 2212 -> 2150 bytes files/opencs/raster/lockpick.png | Bin 679 -> 671 bytes files/opencs/raster/miscellaneous.png | Bin 1518 -> 1716 bytes files/opencs/raster/npc.png | Bin 0 -> 2143 bytes files/opencs/raster/potion.png | Bin 1876 -> 1582 bytes files/opencs/raster/probe.png | Bin 583 -> 587 bytes files/opencs/raster/random-item.png | Bin 1993 -> 1698 bytes files/opencs/raster/repair.png | Bin 1280 -> 1115 bytes files/opencs/raster/weapon.png | Bin 1064 -> 1003 bytes 15 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 files/opencs/raster/clothing.png create mode 100644 files/opencs/raster/npc.png diff --git a/files/opencs/raster/apparatus.png b/files/opencs/raster/apparatus.png index 037ed290fe9d5fd538bd21f9eda35f83d5048069..3cef537e140428563f908eeeb08214999255a7ae 100644 GIT binary patch delta 1333 zcmV-51o#`6*S5$qSxE`z8{Nkkw-N+OVi)D;p| z10ewfLCpQfH z0EB@8Uq-o9PJ>})T>!$fwE20$%{?CGh(n>X`#@nR6Uxtc!?NrVbd1;L{LzPWTM zeRXAJk^&gQ#6%0iLW5R4761!6aXfsHg)c0Oz~N|u!H|#8P~k;S1i>kuGPcjm{D!5a zag2=I#qe-FX@4Q;wZ{TDDDrEtTI;90oTxPCnc60yJAtH4!2A_-JnyLOJI zz(Or(hsAOWeSK9pBnfbP6`*thrl zcf1r`G=H#w(D^ zgBYGpt74qa2@cLMb^_YCjW|DV#j|G?%+2+4H-BP!+Dt$b0lNv<$xVyh-b%oG1Z*N; z0|D>Q1l>k|e+>a|5zs(dszg^;1+}ys9UY};Yb!xZiyn1#1(3^x3{R_7GAk<%4n8x} ziN}vSNQiCRN*)_)roGVUT26z5w_&x`aAVrvZ$NMFO-`^T({;+KjMGg=M=@GkuM*@J zG=DV}p`qa-?%XLLU><5~&%u7FE39=a4_G=9irJ;_7FMT-t!OPrKM>Q z2)yk)azF-?=_XZRf|T9tHouJpz{?mHh4jvN1-{AATbRT-nPo80X z{vIQHQqAU@pS|0+gUe+B*zL8;xY_7_6af29q*koy$%=jMVc8CT`LddPLj?T%yw_O9 zmKBJQ2S>ATo2`XTZ3q3^=+w4wr+;+2tF|4ytSlY%^#ybRbC8%QMS%a_=q&>{C=w|0 z^OHG4(brc);4-phC3If(Tb|T^%e=T)2UdJnt|Zd{|@kHx;t7lw{o^k&$tNY}+xUr7j&M%XS!A rt%56iQj(0zT&)g=&%SThH*4Te9}Z4R0o|-~U&`C+KHrRtf@m)$ z59jThv)0*r?X~vD`*PK)FJytDX`?Z8PN@)=1K@e`@Pd_+@_(|jo#^d7iNr+xo3M2< zACD3U3=q{fHs)h?b{J>R7D1(wj(C&+wIC%gF9UOPxA5?x1Ift|e<_t>v!_V#hyXt= zEoOFnybI5tPrzy|geq7v>oEchNT*Xw+iW#dh5NX5s{`A&n-Q$^FZ2WnPVw~O5vGIb z=~3LjZ$o{3E`L=){D;Q~1j$6!;^Hhkc;LX~{xk4LEUP7ZLDtdleQ<$Do)0+1`GPsxXM5p(b3q^c&LCBOwbExU~w41VTb2 zlhxJPxO1l$*REM{^kMp!J7uxyOL#-wm0Z7^WNdOgTbW|{+j7k_I6^Nu05g|u-co4!3G8puM(CY%AqodVIq0va7R*S*+ zUGth}GJk1ZmoHb4`uk`EdvNbwH<&5izTJtjv387(UcksmD+%-*wdO1dvTeUopzI==qFCLOBK7YWoXA^k(^e$#*Zj(ohVQOj=k00OU zCS`JRhzJi5VFwYm5#e4Ue1!;i5#dfE+>Yzl+epyoiL@2{{mnGqjYPVENY^1R?>i_J z0v9iy2-s}Z9JtfjLl<{rV&W3+-t8bkUL`tfM?JsBGCr|#0oSco22N8jAgL00EkoDZ@ zyz17nzXd;j{1;?rZ-7+lJ;wzR>&?u}?|&q)>u&4$yWr*JKOrkC0z%0fpS({B3F^&2trJGGk+%|9^YV zR|03R4+|53&-dc?&c!ei`}xE=I zUh@oN#R`Okh&M5Cmgx@1X^PHziq2Zf{w6L`ySuBFrP_zUD=T-QrX~kfRe#ysa?7lj zJw~JPg-GbNX+;8o0erK?qNO-JMoTGs@$zMYUC!FW=K08x?{WC>HZXM;7H;7{^7A*L zxOf}bL>)Z11qTkKbJ@RhX97Y)*TQG*>i2&8mT5pL@qLq;szVCxf)razs7{>h*_9wWnOJvFr3O&&lN)Zrfi=u@& z4^wPaD9}PVltX|Z5+o=G!2?@1BMuDNKCrk50#iXI1Uvu&3d%{Gz!0&Mz_sUY(n>kL z?>>;wzK7p+U(bE&HUQfKl*;PNj0|L0t+1x2BRwq*X{o75O@B#2ip2s;ax#*Wl8|IJ z!)!9al$eObgajnS$0OcogfT7-aj~(`pF9a~`4RYr=0LhP8mtAV}E%4`ZY#IM)30GOZ4>g;JB$0MYk4ESZl-Cnt9~@G>5DoW{`g6Z&)r( z!CX3y_>xfs>+izNUE(TWU|;~t%gav4#KeRPWO#TOFJ8RB;NT#hKYxzCzCQH!_TuT& zr+EDMF=PQcSjt8i>>s3DnufV-3JDh`5O;nQrwT`KGJk&v$8-B}H2WF$#QXubUEYwJ{r&w|T3T|xu)Dh(U0q#x^ym>fIy%ta-i`+k9^l@+duVNKMRRjAnwpw$=gu9d zBTqqdx)sssqtK-c<3REN_M3a5P3VEz*om++?bv(jPkZD9S028F9jgUUG>eOi_GtLP zL&Cp9=zoa@&T!TD4J=Q-g~x7TgEI&GnFD0yr%#`F!42`}pweC81^-5R2-eJe_;`C) ze-_~9S51-IY&Ooen=N?=imu`X_f*8-SWFx)U%m`)fxuM&+5Yk4M^0yM%`S$Izn&Ld zuqV|CudJ+e72u~(R8zuH32v2e6_wW@2{QAB?|;=Cu}4nuii!#dRysfeDBG$2H_LW{ zd&_jZ;L?5NP$;Uy&{@bdIr;Q$jrkutF;l+DS-Y74Gn!orTFH}8-KfisKX{G4_0!HoZ#+~=q=%eg@uqxrLTzT zB0#IvUazaG!|3QJtXW08;X8dIpg(QiG;)HcvwcG$mtS8afGjcS^|riom9Ug>PdJL) zCny<5kH>BaFDNL0My+<*@8SS`@Kb5~0wZ%#@%tiTi^ew{sZ{3#_hOq)FuVYAWf&)TettgG;o&xR{%#uzpbNW& z>i0TJw_N~jGOL#f2V5L+0SeUt&hX4kwjZvFevJe4g+#8=dMQpU6FmFJS?o9c<=kXe z!aaQgIm7ev@(`#}%}FH^m+03OK!0Dld#OhJ4qk(aEs@6JQG^&8;egAde}<25xV@v% zR9oHQsLmisuXTEC_WR$p}U2v}0b-ep_t1P*6DvnL$EJ%nmra4TE& z8GK?r_=XP91)(%VOSQe<)Xs8Y3_42}cDT#fI+epY@|>I;$Yrwk60vxV^?zGBKsR^_ z_td+KqoIy#fkt1Cic42eRaM2wc7n4#<6o9|_MXq%0mlQoJYY#N;G6}} zjjVqg*}$5k=o=dw?ILPwYI$6;of1yP%55v#H*G|lS;kgrF)%oOZ4-fHHw*PMd^dK8rUx-AaX01kJBR5J*OTiWz8~dTrOxO6pc^$#(7mLN> mNan}{{fUIaNWNgl{r>?ZwZ|wDcoXCR0000Lx delta 1806 zcmV+p2l4pn4D=3=dw&MwNklE*K}A7_D%3jer7Qv#!7?%mg3)T9zUR&m!LTI#gPD*w z$?rMOIrp4%*8x~3vA3^Eh>u5nTpZ$JV-Xt@gXrjJL`6j*GJi4>5fKpx4-ZFJSQtV> zLlF`Zg5cm_D3wYC1qDG77>K}t0Qh)&!`NaE_~Ll*M6ocoiH4Cd5{ANX7+8m5vsExQ zSq5RFMIbgAS`HF>-GYG2moKBcyBpW8UBlI@SJBzoiA$F*p`)V%7cN{tOG^vRojZr- z=4PBZa|WkRpMOSueLZSxYf)2EgUZTESli0s9MlabWe*$_U62G^hMj*qM7}K$%9~)d zw*i7(r(oz_j!jz@39z@btGamcA|5_`h$l~;u)opKQH+d?V0d^K0|Nu-@9)Q>N00E} z!2{g8cMo^&+`;YJw{h#%E%f&GLh2rhs3YTuQ%xf}?|&I04v!-wX9Pi+0|-ce2%iIY zAxrLqqp}qSZpX24i^T^ANI-jgJNx1J`FXs5{~qt&y~EqLZ=qJJ@%r^^%+1YVc6Jss zGc$Pc;svIsr}6yxb4*Q5K_0jt#b@8(yH4Ol+dn93RwK7=4mm%)#8=-=V_(@65(+1v z%o>1H(SM9hPPy1eVYed-e?X@84e%WnW((Zrr$mo}M0DzkZ#i z>&lfY*t*>po-w@$I5Y{r^e0@T!|+P$$DWk?*q!)0cE;a?N6d9>i{d^T-od4$0S4wC zFy;x`G&NvnYg={x{CQ?6ML97sp%XkbIvYD8uYc(bcL`~MsbdP1p)oKsHLcPJu;m1t zJ$shr^X1Ez7#|}E)lDa0XlO{Q+8Y|rF}Pp)xK7nh1!w151EEx|ftQt)AwNGKiHV6z z1&BBS)Y0f@O-@d-# zr*y8LK7Go%-oiPj7Huio39o&FI!ErHXoRU~4=XsbogycAad9z@965qmZr&^r;OgR% zn4O&s>V|`ZgBTkdV`2#Ix+4Z&sekGPH@4o3d{wa)ys)qkSy@?-%jK{zH&4{`fqzfe zuU}77jRwr!yLVY3(m-}BD{jvZr1(9yv`O-zjddg1Kk zG*(?*&8(+1_y?uHBcfX`IA5B$Dm*VQkJ)c75R4IXi2ye@w;HNY>WG;+1xQj2=?9m@ zA~Z5-#mEVsk&yv^e}7n7Sk!0x$BpUmdI6(i{h+Y5S36+rVA4XpN98`_-D^4{H+_M0lUJ+};smK)y z1r4Da3(;!{Fc)r>@oXa4CKH%3gu*5@VsamAjZ_VM=W&Q7?rXviA3lsYZhzggx3^ad z1Onp~1<(USQG{F82NbBFDWt!PC>z5y0(?A4jj{ z0KFlwa*-LBd;M!6tA{Mr=b57Mx1xL0MJSiy&o}Ql6 z`DzziuXPGOez?I<{C z>^#piHa@f(eAN^z{vx-%s2m*~)wD`cyQY~zH>j?zE}T4hQd4jX zwo~M~z;zZtAGEfzN`K_q=nUN#sizkd6lkt#RP8A#DXidx*48s?*}iHcTFo-aNyIHBZGPx#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000EgNkl6%`P1L7nMHCCES#qK*i-RU0vC-3CExWf8+FvNUAT+>peiV2ffU0feXL z-kDH>XuwRzFMfFEW_j=XJkL4Ld(H_15cWCOX9Z`4e(Qyn8+Mw6B;OJ2;wumI2l;l*+YD5AE z2>6NN5{cZZ*Ei$Ut9i`K%wu+T9$xP(-oEu>WW(trlra>Dpl@*__&0@ z^70xa2$Im%H2|yC1+&?Ku`xS_hMuFR$An|Y>LK7KTO%W)10uo^_AS{|?jBv!s3oFJ8QX-ToRj+Y}x@9zjNi61xibqO7bMq#F4u_DKZvP>%@~M&pGg(9y1JvF(UK_ zIy*=3=+OweyN&d_5gi>vXllBPjp3Vp(a}6@Sb`vVyrkp@0&-wsVG&bPbEJ6YgWx99 zpD-HTlxG*Ib&xtc0ozFNvsJ;{+lTP*;UFG77(iRwAdwlywQKi~m8nL=H&NqZlymXH z1BZPD`GuI9dk44s{{g>$zYq8B^->yoAeAVPowd!!ixr4D4@ksvLuqLR+S@xR0^aw+ z?sEN2X?Xd`%KhLiE!||s2B_5qh~o(iOO=o{1YMsu+w<}{w>zEFoZ1ZDk0BPzAxsg!Su&yjZYCv(v{jWSP+NNv4#z9BwsavcuWlE`@0o%7?z z&q1NcnXa$D3>Lho=pfym5=2GDX#KbWbs#Yz#VrzvA(JURN@Y$B%kuK&I~4v2a=&|B zhGUg$wP(SeAreVy5)*_TUMwGxkumP&1u1|4Z3vI!@pG4N(CKbd_&qS0Tx)i_KkT)& zXXvQ^+WqEDk-3{TM!a8$K31zQUAjr(e?bOxtm&$)G+eM*BWOFmc<~06RTml19`v5C zG+cFceLw_)_JY+mT)1$Zs+@x>u`4Uw@*=Ym{LY<6sH&<9oxu6?*C_mUGT`%o@)`{M z)~yayR-Ou-z`1i*Df~7vpmnLXuLbKf%*>RQ2@np$aCsR^Ax-KmS5`p(Ybb%E=2ckyFsb?5}t>h0LK?-2Ix zIf&xo11R2Ig55>?sj=+Gu3h`M(X6mw4+_|oU(AhXJ8A9MQ3RDLCv*Zd&3dx3zGrBH zVKP%kY_XU^eiTwU9wC@CRH&~iIS0s6$}j=o{&p%umeK< jKWHxq6(HFAUkLmQ{#pGRx(|VW00000NkvXXu0mjfLUWRt literal 0 HcmV?d00001 diff --git a/files/opencs/raster/container.png b/files/opencs/raster/container.png index 7874606ab9b905dd3afc5e58b929e586241f3fd5..2a6ed01eb9969129cbf9edd6d0f404464f97cc92 100644 GIT binary patch delta 1450 zcmV;b1y%Z@4E76Mh z**CI~1%e47Aqjy1fv`g&5y1!%L=ccLQc7uQ-55rzLls-5YOP!C;&f_dI&EM z>K!I7ln%wg1xDMa_hp6-wOKCE4|nn*_r1U8JnwnWIqxa}tD-#td$QeYl8<-gr%=Is z9o2uCr=zy!YN>XohHA^vP_5Z&s>PwEnzNFrO?DO4WK&U%Rwd=uiO0RGW%gL#j|wM? z{Z`fa=^dqbd7uF=M%pkp(vD|`wqWMqW=sz?VQSw-Ozx@2#GoG!cGqJ3-8J~Nrvw+9 zY{=J$##SsKJ}xd-#$!)^w9bsV!$CYh`Z|9e57uC6z=z45)p)qwgZurJ81E~`z1~vX z-sZ-xq7;ZZtZA}##R3*S5U{C2PxfuVvtw^!@+~(W^%f%3Hd z$1M)5F~~x(zzhG!+yXj^*D4K3LvIwO%o5w5p4uK2e!V3N%{Jw1zFIg$*2WSNQ2>8g zT&$Ol)>)J@SGKzFgx+@opFY$cF>(UG+HAws%?=##tVW4WJY!ezN23XeC?HoW9>3Dz z#M1-Kcz$}vJe(xl{a$xi+ZW)M8m+iMKi6r|ms_1USegoxlsg{DiLe4Z>GHnw%~_Z| z(T~|PyYcu?8z%b8V@6KkV*v}kt2cjR)SrRT4Q8D8o3Y!ahC{*c3nwD1fHmpzYb4WdqO)9E!!8{zBuw%;is$g zC`=ZFJsDvgAQg@jnduLMOSU~6{CGtQ%C$m@u>&1W&7-NIO_&;PkC||>A}4?Fk4tqZ z(+HRga2N!CZCkIxiT4~Jzg@LTbk-=);gh4yn}pUX88%nQu&GRn#u5nvMPk$!ir{w% zQI{vcIwv1%vw5h_;=ya>qRPU7PMYv1V+UG2$`@0YD=~Gw8h20H@XN7G{B+oi8y}c( z^?(r<_Z#s2o-~XOq~hET9nOEgt-)u#YMkm;;gg^ON7|Dx(jvofqXa|sBJ8abz?I5= z!B{|@TlVs|AIk9i70>?yA6(0WUCnyQSU{jeKKEd>2oo17R~$Kk@APt!tzpeE7T~ss zX6}9N#3b#&N^D<%zf+NjG-<*NV*v#w;lo=;Gcj?oYT0|f7~WURf?j_T|B$hO+!WzJ ztyP9#sR6Bd$!K=S(Ug^hjdmFVRw?Q;rSMxMsLK$e)+9!aQ3Rhsi0U)}ym|quQu(OR z@#wS9MX8#D961|$VZs1o0d)6@>vpPfyU&XoTMPcF?U9NMIp>FqH5hTLG3-*|{X8Z1 zI~CaLNWvg3+LO!!`6hp30pvwbnlyAX=*G>iqWQ+MT=*`l1U5-x!~rE@J1)?Ou3c`S zC!Fr$6~VWg#V`ulVH*(%G@^hUmEh#r+6>(4DaF@xXItoMq_HfN*J!qr$O*j1D1@HR zI=Q5IfV^CmBKGZZYjLB~g>Tkp%(v8~!uw4kG|-7?7P5Rx7C?W-D1W+a_5wYaeA{4I z7QD|WK%Rs>yR4CnD0XXvcgR#TMo&6Rv7JOt;5})4m;?!Tq79}|r((ODH}-|kfJ;r5 z`IgFL&lkhHQ@PM`6GoRUfXs0N`N{O0myYA*+KA_TA>m$yuT!v*!i^6*3o^PFkmAu` zl;T{C9-mfe!xn#;NbsPJ1D7}y_Xp}irIi4zMtN^_nhy1-#y>GV*rft7KKJO zJ+w41Yg6QplH*C@~57Vxy2RiV*UJBnrZXd>)CJ1|gpm!uF+wGU>kd z_XtG!kF5C78H*pPW6)h?!S!WkTwNNCON*m$aX}=`&o|-B zya?>imm^WbUKuq3nN*ssm2*#9vN+scnSj6AO7X|85^B#W^b zVWQou?a~)i_D8J+_^B@0t?U&1SeXHfW5q8L)a-7$))x_v1nA;ao%lj=l=%74*-G4U z#^HWr_JHiymw(5;Rr5jcu2MY?mxN)HokLnE``n@wUGPT4BLSOM+;^f}g`3r8++CA8 zkokknx#)2w_yqs9NQVOjq1czJMt!mvCWWZalM-$TOw)_%4-^LDmpU7sv=$CD+#OQ) zYs)NtgLmYGU~jGld#0=5jA39=u=VapxFwLOXS;7KGk?O>lmi#Z`bJfZ*P0K?KA8FI z;B8qdY_ZEIfo{JE)MUP|w!YzTL%ZFR?5~42PYFi6Vi*K$QQW^b_9o%?9tXM) zq~YSu1b>`sjmPQcI2_v;i>?L>4y}*I!B3;mQ5T8!8Y8}RMqpQ!0oy9|*s@56rum_0 zbcCROwi;`TRR~iA{^Pd-Qa|*tpNKVX%?f08Ns#)@^ zXO9(+FPGr{Y2tn(l%0Y%mMBn@$w3z+dgeEQlt{^=t_ITpc;C7F5!HMU{4?UH6=Xbz z%6~+U{3ejB7d1FjIcy@H-db+N+Ds)@PgUUKbUAA6!Kg_IhBG+`)ixQb5@o2gO0gu4 z!$OM$@0lf-7a0hLQH-*1F=iP=NLLD=ld=td6Cl$|y4)(p@wrA^T`?J*v-I$0GW47` zCCkuglVU>xhxJwo*2D(l6N?zDq6h)SB!AF7{U$(vv}+j`HJMA*@iZiG zj5tp2c_RULMhG!SGag!w=^WO5fc~7MVH~yb3=S5D;nc!Nd_knAQ;iN5Up1$)Q-AOe z3<1av8V8*uz%gtB^cqzh&h&phLxW=##Org^!v=p}CqSHZV*iM)WR!7&is{{vA;*z& zJ=$k#hLt%5UlcMC+CX8iw~MLQTd`TeUimyJ5c`X?=qL>FdemN*oq{jbPQontSg0lJ zh0zeG|IjQ%+jJG_1&zmZ?hbsBW`824a$}(iWZd2b{dyNr^T^i)U~5`1_7|$KDMj{{ z$#?=^pqc=)c!Ea*@{0idDMl`IZJ5lF9#CMbUHXQ@c>{OI$3ZO)@cBaW`7$yFvsY?K z8HU=cH}DF@c+8Z%1BI9w{o~XSBw7_6EOc3d1bnniz(%-LW>@)on*9d>L!A~ne4Tdy0000%Q(MegORbpU8XO=iTT3LuXm1Ht5nAN^LO^GK> zrS#)kXv5t~Gk-SfPSFn;M`Y-j7t2n*nuvS5^`3+n-i8;^nVr`aGN|g^OLbjB|;*XvCS(0 zs(h8P;%C3EcGB=iD+=(mxfH{Ttmv;uCGVqcQ=}S4 zlf$t`BS8W;@Uo{i-Vvcq7Q(ZKhfe%lXQKn4GVgO5Fi>T}V6~ZsQ<*XzdSx$eW&Qz9{!ypmRWj~)DgVtCf zRP2C$Px1K_A@#CYA?P}vuXV!*tI}am#n39L2nEvfC?11$Y+b>NV+;fuv$A6dD zFfiYYWr;HEA|<<1Vf31F%4BYk9q>N2Q$453?wR>CyjH|PQ5Xk%NL4zCA8d&gAchst ztRod$M|p$7FLzw@q25#A3vPjjVs4K#icK{;oRq&-0*{&m!mMt zh|6DYM?+m1S`wu0vQwGwj1EO2J76N7<sJn*mdUT_-`x#RInq9E7a z^jLcNEU+2y^3gp^zIcp@d)>Hp{wS)-a#3EGg;mR{(Y|gewymkh=9W5aY^uT1>OACH zQ;=`dw|6B+qMR~HZ@^qYZG>CSb+oESL5oj9dy~JGpFFkJJujMN;0J) zVDdE1Y8z4xWzwo%J|5{I0gSu@ALu@gzN=rM_wo_kJl~1yr+@d+T6iD4YiBdGQPLN_ z7STH`@Qf@;$a8&cNkrR*W?KCty%*@r{|J0Zg&iddA);6Tu34?)%y53=@d6!QZ(0Pq zUPG&Yxue;v>+M6p2o937rY2wtr%ZulvBv05WBvUEh!!(J;B5 zd%|xP>##XRffychz?Y&+Wx;=rWCsj1Dg{2_&15rb*#4(K*aGT+PQdLji-TOXagxc! zabncOh$d5sH>3)$<%^%AD<(Yp2 Ys`Lns?+??S$N&HU07*qoM6N<$f>j|v?*IS* delta 2408 zcmV-u377Wy5y}&gdw&TzNkl~;$f3Scx&Rb$#?%- zf-?#rN+#}(RY=~1h=n!e<$ur$JYQ^#3dFamW*kj6VV&6@YA@ak`b;O_*H}beZ$gBg z-7{f!JOG_Y@S-S416QCLg?beVbSeakg(E3yS$&<+4;ON6$kxclbV9H8${-ak<=fD| zC=It3CgaTPS$`<;lR@jnYftd;9_xq>M7~mtSt8GR4WBy_Bl1MFh!2}L4^|-$GA{eY z$Kb{Tu*xM{+hW3Sx6Fxqw>xYhxKoyZZ_Ii~`P?_VV}fygz5_$` z1-Q8&8E11N(Lz`db2)En{be|o8jd2YbwIM1x_4wnz7p+f?MGdlviVhu?1 z^~NTX7DtkeSV;o-N-x9i*dTP1`v)8$SQjEks3+$aiZvww`bUIJ+;@lo{-q)b!wqxs zXvG{RbAJkcy*Li1G9$3fqGKq(SDl5vVh00$GRuNPNugM+_r*?|4u_nf*q;!Lz3~Q| zOtav4iW%FZ{IO6jfR@MZo2ZRXL}>LDOYOdrSKlUE&`*H-2?HZ*itu!8DITqwhu(S7 z=pnVI=fTokCVL9ronc~Vrd|wAdx_C zm5E>Njx*w_E0)Rpsw;*8?_ZqGWZu6x12@W&J^}wO$BLf0F*u)V$JuNvDM=tYqV=Tq zS}az+2bXhL`pKO!Z5yfu{78dH@ayjA5cCn?^M$dPZ8pGa&|!@|aGdtZnJ*33V3yt= z&VL{xI%@z!d!<4E6_@?1l*5Xgt}UkoKm`&m5e_z)18^bFirWiQkZLlZw73`p0|O9y zd7?APIED5WyB;F)jNX}FR0Nx!k_li#m=d`n4%8gh;6(9FD?<8byj;?~DMHVH(>|xI z7Gn-$UM%qzA}b{sUlXv2HK&4WFl&*SoPWgJp?9su5QhF%iw5h0eUT&ZfS%(q#hj)v z5bY~^x;HL_$(({;D^0}m$bfNhgG@99oT{DHJU}F1f)ERZC<^dlz&D#z*hp9?lW^eA zc7HlW1C$n%k7&I?ENrL8Ci8x|ix^EW5#SACN+0{2(%u*qfJ+5&IG%3)q}4tOZhxmO z080!CG={4_0bd^~M~R3HKeqczIhWl|kBZA$PqE!BGV%RA4hv4FM&V$B8FT#=sMae8 zfDy;iOpM?T5%3m^AKIgII7ckGJHs;G=M%wc%~$E9s8I^gXpk|PuhL1dMCk<^`wK*P zvQaGIp;XL4u8<8ShjrgAU$6f8rhm(UM>S~}tV+eh#mUGGR3bqxMv=w`Ufd6mKoCLRlMd=Dh>++pW_iD0e=Y!XkjMfzcDga%v8YAn-w z!@%_zb~F2kMz0sf<9VYCf8SPvSFKeT-CT+1&E+^;l8lOIBUa7NKy}d^6n`qb2@_hz zUMGXodedx^y;yLi*fE>5aF)&&o8yf*k!?dSF{ev&qH!_DhW&BDs8tK0V0(nF~LD--|4p8748IlT5W7l95ZwM**QU z-J1gop9O;_7Y?HiUE5Y-UVn-O7JoVRIm1Z626U1M`6pu2JBW@b1C??<=?S*h35}@aplZ@w63T?ab_Z1=?(%Ei~J-zR+r^q z-pk}$hQnJ33GCnZT|1aj*81J7?YIw1u0dIaD z!SJI&M1<;bbjuR-9)I0JK-)i@_u!{G8*#XG8UEZ<&VcJRG8|}az=eaGP&+RXaYV>8 z^M(L1@;`t}S?!|eLpE7HdJi;X?58JqJN6p=eJ3z4+lj1% zNR-cxMO~2-H3be-lBu_lOuZaO7~&#=kP<^?{|E5z_BLb1{C`xKNf|0+Jj8LnfRg1t zLNotOD<%tOLzq}FVhvQk>)Epw{~G-Pum3TMzYSeuH1K5L0!|%jLr2SMY+GB4mNivq zTelSZ+t%Pp_jX)9+R9{3!6`FKT}jYN1n*RA4+8AoFr#V6xMP6w^{E{z@zb*b{PX3r zad4`Gzuq{32Y-ECxYu(Kch2p_jnf^|f*;@UM=Z*Xg+?O$_jH5klM+mf%qaC9DG3iC z)W+f=5!~qG0Vea`3%+B`0z`#qV3l}5$z_ksXdK%V(uR$;P&{0e0(&qqov#<+{^cXT z8@zMfVw7Z9q4S}8qKfefEtmEA5=8n+278IH9xuzr(0_&sB!=rqJ0{^oM-y(J-Sb)6 z4{WZ(+NxY6MFt|6*!g;5z0`iI$vmJt!DlrPt&qN;*8F5uK7QP=klBn~+wC7ZK@v|fAEd+(}K3+aSR zwQMX)?SnL>bSz9H7%_^xrif_r3;lWQ2J+=IV&b#L=vX##J;ta9__Ex0&8Q1z@cL diff --git a/files/opencs/raster/door.png b/files/opencs/raster/door.png index 36ffca6d68c296cd5f33dfe9d6293c37a9de9fff..aa48858efa1e5862461f899752a2c0d91b65a2c8 100644 GIT binary patch delta 1522 zcmVh*`X>N0%ywp4izt^vAEDqqS3uWA0DB{j+R)T-P&aLSbZXfN! zjmaqHdj$B*s()u$x309Ahz$i0oSm1q4#gR`UxMG6&0ulJhutX)%0VML28<@mc)eG^ z@-`Te5wr;%9IU?~M8D!pZ)nK?mOK7Z4XTIF_^EbdL=SB`XGl9Ku#rqLzr7 z0s=P8y??jH+9fzmJK4Tb<*&lemwC(=?dWXNO7K%fD~@N)a2b^MWD7{SbdRX_Wc|vJ z2PM|udbY2Jll5=(+L3l@Fq^kvzF@)0yct1@s%9H%I#BfMMXLO>xjc>*c+8Z9nmw-v zUntqIyTgE8F@pp@kuxLCt3=rjP{Mt3yh{q2BY#Z5v7#VN`>O-D5u9u%_^zm4g3o46 zjR~N5ttQ;zyj^mk5jfdC%HSgry#$}h7|~&Gz=48SFH*w2zb}UAoDGKy_O+|FS>*(u zW3~@RI1Gn534W~0h*%>6@=O51-`g9-!K_UZLHArPoT}a#(qW|2j)5ePN=87^t$QMS z27mHiP9*rd6A>oBilkFZONJc|B_D^PPls-=4h5EcdAC+NIhO|6HVraPHM$&Xs?_*j&~<)z9$;NO2b zjP0eie_h3z4zM*U68!3DpyA4C;Er}0uy-`ERyo1HxY38Mh)JFU876?>SBCxAn`R-x zvVF6jcREx^3o4}eRwUWUckno{D~2y`4q=h5wR)d--0feRwVdJ z#fyog347RS1U?njqU=#&z^lf-m=;q}4MJvx{3vFdOeFX+d)165j2Mp_Wmit{$%qDh zu2%Fj5d^2dgQf-r5PXrnXvX6PX@9X)6K*5htMEM`HMX`XnG3BFd?Ktypb-ISr&c8R zg#qWw;*C_LD}yZyaVWvkF8*iQRYRtF)v5zmwY>@_M|}Dw`7NLaB(2t& zjOp**{||V@-3%|+fB>6T@wAgYD%Py8E*Y}EYCmg1#|AA3vldVrf`%sP7+ag3)_M{B Y0nNHJ%Amm=Y5)KL07*qoM6N<$f^E3(g8%>k delta 1611 zcmV-R2DJIx46_Z8dw&KZNkl|Rc-r7L=Ih;te1Fm*K8;G^X2dQ$2-yT# z?cd{{Qw6TmYTt=S;-l7p>E+2L3G3Y+eAMU1m0lk%_js|M^Wxkg2c}aNG`Pfs^8eVMl`EY+Gp@3f-4kMS8FjVKjdVf$+;qG`87kd2Y zua?jewc$e6i|d1aTqP1Gh(yq$d*L(dcAbk|33#o-S|;LU!@t3JqPsbC!Lt&Ub=e9q?g| zY-kNxXn#9AxRj+?2@7xXKew@o~eeWgvPH^sgwo$@#gM^EnPR!Mq5j1P_sukdb zyFM6D_WVqjUm;NnILpr9)Ae?o?{H!!Wg-Gq>VFAvyz=gI$SimHh=lKd)Bd{W1=$Op zv+Pp@K3QkSYC9!lwGjbR2?Xkh0LLpQ-04m)PIq~?S4|E01(JQD&W4Fv8_ph*F_|>N zUkZU*mmz;0zrR_J4ey z{>Xf@Q;FA|p7W{|{63>}ZO2lx4U1_jy#=f|95tacOv6aT>Ro!cMUDC`NJv6{IU_3r zcdXfgqg17UFVtHw5H%7BBaYXb(eKy7DQMIuVM5a9ms%uc+K;AX%r(i%RpW%)uX6^U zuOrZ~fk+rIUu#0Ij|k{1)Dwu?^?&)rv|U*>2Is?43iwgFetjX4NQmI?9&Z&Kr4Wb_ zfm2O3MfSo~Q``e$N%I8XuOu2Cg7`0eq&~fLuUO zNbq;JO9M$;uHJ$u5m;!jDzfuQ<-@}1R&3gfflnnwbo=$l1qDneMRYn#B!3XG>hkk6 zOdPL#Qu(ly0zMHJ(B;!1OC%=aB03xuuxrcID-gD7^T%kCIotW9j;5?{?D=k;Gx%6k zj}DJcQDGt`piM4^t*R6P7HyuNQSAHiCOcXw;kHxGODX3O(L~kg<`U@NF#+{XJ?f}x z=>=RPQ%O1u2K5S=R;diu%6}3Fgopq?quBRCwx4dX<9$xLrmdtq(O^+RhWC8u@UiDC zJ9p0DqY)i4wh{^O19B`TVu3(-7TAtC0-B|j;^);=(trsXv~dC%jS3iv=y4>h!%&F2 z4rnppuR@=%620C^8DyqtZuu)kx2O(Bzo)vo${RhGC1icE4k}LoK002ov JPDHLkV1lHH7Y+ab diff --git a/files/opencs/raster/leveled-creature.png b/files/opencs/raster/leveled-creature.png index 4aa2c56cd7bfc3407f8aa7a56830089ccc022461..ad4a7c6f837a9946e420ad59b519bb24de3eb2ff 100644 GIT binary patch delta 2049 zcmV+c2>$n^5#|t(dw&PjNklwb9kVdL*T=RMDP&hveF0P?VK=<_gm`xt6hzu<<5rC za#Pg18ur@eC1UZe=V5#&;8pJOg|XfQKAgLN4}LO+_pYDAZ?Aq2^H+xP(~CXulp7vL zy*Ax;B>ratjS=tdcPI!0sgiPyXSGRK$gvBGrV3e{C+~=d$CKGf-hDf4RD*fj{iR4~Jjex_Hih9Z)>r`c5`)mfGJlQKR=(4Ub_~#$p z#I=hjaDREY6}^cNs$CZJH$`F8X$8=DJdXPMdW6Gafr!m!gT-Qj(P$LFH5v`nYBl6? zIiv>3vE=xdv5yxsJ-VH1Jl%{A*E-<`q7cfU`kK7qH#yYZvZR!pC0ghr(l zz*DJ|0PgX4V6|GoYGebeR4Pz;Ad|@;l}aIzNPi#_iEvOX{yY|N{PC4Ub$XUMVulXa zeW6a|v2bI21N_a?O-O~^0$4*s1Cq%ksw74XCgf zKwc0|{XFoZq9PR2dh0?j9?W0CyO&3B^U^To!x-Tl!=XxB+GEiT5I>k0!L7+&ymq`1tuY^(BW^O68g_#k zI;C7VIfEAz6d*r8AAYA5orx$W`;TC>vkr-n6NAlBO!XXs%cNQ1e%)m=Xx7ftKd%g? z1n`ND8bn=Yq0Rz2dF?9mp2^gG;8lvRTw{u`>cq$Oz>N^ zPc&-vH?dd@(Vzz-U2$}_Byn@{BwnY}_caDFbFvYMcuXMH*3yi6w-HjYNC4lvcYiO$ zqGAfDlO*|8@Uuxj+(y;vwo#mMFFAUi>&(t~*{xK6JRUXMwD=bfK)QEd3(GDM}@qPR=C6C8EVd zwJSYKWy+SF!IM5S%GL7wLKkHBB!8crR!44FP`Gr_0+B%}t?X9IHe3M#i^v1y{y*^^ zRSuKRYt?@mcA9X=V?n^Gg+s6W)T)+mM6y7D!+|5zV>8aQ*7-Ryf1gc4E|cBnu%QSR zNC-hgy)G^(5mpH=?tA*4=M8@*B9AkBIF0HRK6!V<0gI;WtxZ8x?XiuYYJWSl)D{mc zIxM=ykjwJ4_izvvo$8B>7YOvrOz?2rQb~lwV>K9*$q1lCg0GnjC@d)Wh{2pj)%#}- z`!E=HvjV@{M4&F{oVzj6`|r6;Zk-uOVxlVs3JK2jzf-P%Q6`sv!|BJN^E_~FKL+L! z6c!c=oxqQa#`1>`jhzKa5MF293#mfOlrl(DH)gv z>;%sJ&ji?noB`|!Qqg78DwY_$JH*bH&u>zIKTx8T)CVeVha9F=zg4$NH#||v|C8%1 zHxHieWY3&D6Fy8JlLLHJ$x83mR_Jj&VneN+#EeuMT(2i_GrBw3NpeS8<>GuLsAj)aya5y$n?^)oi zQJt5`Xlp#{tuza=!DCJ%%1s7Aq20T8vl3r!=dW*T!X+*PD}TYV6M@B?*cJyJru0}x z46n9D5Vq@KRF?_htN?p}jG6wg36R;QS$^*SXHolA?q-yhO%8(!4w{mp!u$>Ab6WB} zT!xn>K3WL7}&?`?##~a&OX^)*ar)X zd3ud8VDm5-f(Z~1et>c8`cc1=l1A8x8as-U_*KPmqE@2qk6Lcj)>VI0RVC+FDSzL_2s^CJMNaF@QjZd^ z^xDTO^X%g#E?YdH$fE{9Nc}pDZv{MGk*~K!^Kou>D}Ma_ow#!RIlOza4;K%1;$TA= z@+{K*pkj8;MdE)Z5OvwE9BQh-&t4hAnVrpOFUiL`uYIzm$oJ1f&6T)xqzlKkR>3Wc zpZs44l(?1qKYu^74+k2`;j@}2f{NVCK$LdDZ#CcOE%W32cRLaD*ucLflbDqOdMNs& znk5$C#rWBc1up#b^lrp_j>+Wr_`cX-xi`|c3B6Sz_$}h_oCMZ-lo*Lh2<-7 z2A&VxVzGcq1EbLhtyYV)v@|C1DP{O~RbI!`vwy`tv=@3%P36tEN)wcsK_-&IW--!T zix1v9f?u9Lj&lb(aC%o08p=azR2(gXSC)iPUKBvU=Rwf#f!%I@9Qkx`7CIBi%*;f3 zdOC?OjCYRo;Kl7t7~a)_Gea%dQxiehDo%MM<6w%PO zi)&t65y94`O}KsgHnz35;nJ}lHB&#JXnzJfHe+yL7xr)OLey(VZf>p$&e1c0b^`zO zR~PX6_eb#V_jcg*eI0m-$ak;JgHII3A1l&rHeU71#!tc)0|I6Nc_!h3D4HIz$Vwvx z*wa~yZLN*CaJ(NUXo23%Wq7%NGa70)sKnY^TTmDAz@XD&_3G6scvfZx-aEY)zkj*> z0^U5h4I?`maJ;h`dmGoH$tS~Y)Wzqt;)HrhP@^m=MNtsU_afkR!RxXk-{XM8W>M2# zAN8ZLt_Gz+KWvf-85tQ^xpF0zELnm)*@R0+yK(+-*9`EkQZGtnEo=te=)8LYk-1L7 znlg~#u*#DKM?DXVNubCzShZ>umVYi?idCtp$j#2aRqT+bdZKyQTVJe}_PKJO8hN3p zg<{a%RJ&k$PjcimI+D#o(Ca((dcA5iT;DZo)~G7y!R^KobIMZ*m<0GJJ3IRtuR+%9 z%rhH5E|84~$p&~u0ZyatV*-C{$tnRh2ewe!Hec?kDS^{$`t5WQ^w*U{DSz1Uh>&VH zxukXtiH`c69T3x7kV+9xtl=^V6Fp@k7~t4jAzb9dRp3L1|tI3wubE3 z8d5j|zn(#$&|!W1RDUCW@_*_cT&Dhhska`x>xw}yL9f&OgT`kx9x?Efz=CtSwZPJx|*?$->amj!2$;O8U zZLXS124{Esy0oiX@>k%j0q%qZiG>Rn!eY>$4M}=DQ|v-W)W9KVW3vd%byOlz?VvGE z0{c77UvQn1Yn}|wk*l>Q7v#=ZuwVf^Cf(GQpbfPi5jH_LHt&guA0W{kqPkD9x;YD+ z0Upx@mjL(MWYiQ=e}AtHKsJ1-0Vc6%(IN<$X=sZ$(BP*7i=e%05pAExqUXpb=K`N)LS67+wfUB%p}0qdo2(&U+#uXU`Mp#Dbm& z9Q6<#IxE~VM2em@z!~6qb$a^Le@%dtKg@eO*PDsZ^}Xc9?4q&BZXj_AI_Pq9)TlEE zm^&ar%bM3RpSg0droNC!*xKkLIl~1X^o0FYA$zH%&Sg~RS z8&UL0Bxdb~+;$0L;iDDre4GKcRsx%`k?_KlnX3fKn)rx@lb#!AGO8ibnC~NJ76D5A zLk4CdJQCL&5fPa6VUZji5x%p0`Eqr8rsx0m)Fq&oVmbU_LEG$y6kVL6W7Wq=h#ygk q_46%A&qe5+4{4pd$=?8Tz55@NYw_ktWMjYp0000e)Lu4Zl9wqdTDmADB8rN-_> z&=&|iNgaCu&mM#>o<#^f>OsYWh+t?ENhoNF@U;C@p%{McS1pqAT zdM+g?>Jo&a;B*!}9#0gxYr{oRyt@sBM(uVR8jS{A`Te6)QGblCCBO{tbUNyw0cy1x zWHK2zWZ5G1061Q+*QaDQJp#V46*F80Wq<7TX_Y744$8)(H zI8RPK7>2Qv;D#!o#mD0@Ae?2{{wlcc09t%F96~mm1@#}zyP_zYq$8jGZs`=@cq)|w zK@e)&TU#5e;!7*A2;a5YUd_V)44}ok-7X}PNmTZVnSc1N0dPE#NPxrP$eK}d{2M=d z0LLHh?_tkwf2M)|sDKu4wOW91wc(y<;okyi@n*9L@pyb7dA*M`@p%9oN0)|Uo;P%; zkOsBjHx^lzKi7p%D{$s^zoDB-xm*VI>eN$YndndH5M8bhb#Es=REPrv w0)dw!jwkE?2R@yG9jo;<91gF1sE}6R3taM#(lq2t-T(jq07*qoM6N<$f>S624FCWD delta 566 zcmV-60?GZK1*Zj&e18^6L_t(oN5$98N&-<72XG&uH>h5qcABO3p`)o~m^wN^ZCo3O z*|M!mA-B46rK?;hh=PWpxDi1}kO5n?5F&^K(bZ|LU`#h{X6}5nnB6$P|D1d7xsDD1 zbXr|!9#7OxQC-Sr>$+X8C~`H!9d`R2!!WZ}s|EFX9nQVp8Gjchs!4za-fp*HI2=N+ z*MnRx2d2HfuId4n;k8-~(&;qp8jb1(ScPXY8E`lpGqcI0-VzAmI|jp@YE38>S0#WH zT=4)>aYX}=;EDwx#T5yFR>drnW$aDSQaZ?Tu?8~G39<1EWUsZ;_w5SU8EiFyFX3xxvseZJ3t-yanF*8KY< zRRG8H`8-&Ujy|~cHk06zD!|7Fg8?9%Yqqf*Tyy|F-tYGzo6UmD>3nBGp>@(XU;IvR z32;1>N`cL4Wj8lA*5u-X6&GRQU@Lv_+FN zXxO({BpoWGL3Q{S%LT(swZi8Wa2_AORjXAf7K;!H20yvaC!#}zxB}sD_yzrgp(yHu zo9)Dh3NLX0nx1;MAa*k@H7+qQF!XYv000IfNklK+1xDmAH;Hx)J~q5sh+2R~E&2h>$`!@=#Hu-y4Iq&l}jQFc4zX0$?P zN()GY+M!tyfFhTQWfX!BbWMhr<=+8^Ee%#UD`3N_Yml+18DhiAfEUE4XDk4JHJnf1dnKxb~i4ujIeN!V8rVg3(%{L&%Z5c@YZ~M+EL^P9%4*{q}V(z z{i_$90FgjJFLl&`7*jo)kpL}ec(66E68bva@U+tn=WCvNYwm$BiQfr2(#9b8x@DIE zmzb&8&|*jo-wR>^dEIXTT0-A{n7%X{dfNYiKOc=iQ|+@!@GnzOvZJP=J#dxGPKW6; zAuaX-2zVk&%r`{)CBPoySZmZ;=+3J{9Q<-)|0MXPjH{^b%-UtOT;xXbGcc1WV+bx4 z8b>gma)n<;gvL!NCr0mHe9ghz&c2ugkBiI#6>gvuGQ$|EIZC@ly_k!CTr5!2GAuIJ zmG77zuofp1bEhp8a8Tzj&rPml1=wODYJ}9g&MBr2u?`nj@-4Pk)!a}pqb*0B&w+OScpA;zsIZKIe#$dqnrf&DvrIrzrR>mb73jv9iS zRIAvgllQ)F>G>qUthePFb)oeA);I9*rVGv;?T6a($56822f(EyePCC|1h}4v2T!+0 z=n4Si;e8+4xKj#X>;4HYQ;xJ!ZFae&P)C@v_oLL-w6ymJaAPABSqsH}H zK$Ipv2Yg zbM;T)M#})4s_x}~;2BBfVAMrWUNqa^ObvuH~L>fveR5LNgGGOg>L=dFlT+WyC-iO$(kFgpf zsOIDS(A?O^&3Z}JEf5Q3-Z@9`s7ZQ306W`i+UkZzL8O6Y)~#Sx!B*d1XJ`XBxawM eiN9dad;bC>OqY0Jk>APy0000j4ekq&B!2{FK}|sb0I`n?{9y$E0004VQb$4nuFf3k0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv00000008+zyMF)x z010qNS#tmY4f_B94f_ELcQu;;00h2CL_t(o!@ZVWY!p=#$A5qK&g{-icem~KgO(O( z!Nev?u|-Iz27M6UG*KdI@DYugh}f1y4Vu(oVqz%Z3t;sDUi8V>XrKXO6oNtdDBUPQ z1u61nKbD4VyJdHFX08w0#&y}YyXE5~lik^K&-wq(x%bSDpg`;1;M*;wSna0lRnP8a zywLb;(+XLa09nXl&!ftaSf&obQ44QZykLMgzT$Y% zkQ1-+T!z1Oy6*&lUT8q-x|i~-J0U%X4%`jP*@4q-Gzc(q`6Az^W6G+j?px2YTx%3u zY2MDroB&R@(IDYX1r@-WY`>-x0;pTY7GO)3I|>{UaDN8aGbaE6iu3x9C5Q6eYX@#PKB+e%0Y&MS#7lbndfXqpoM1c8`aj9*h!FK97HywDUSgFq0+xKb$`+uX=mlE0OLMZBpi+dOwl)Y5=CQ4 zz5vRjLI?%{RA%LhYBfWg4lsOy`y$;e>4Zm*bkVXE4!aP!^cw=wV6&O$vb<+EdIv21 z@iU&@2A6=Jj_xDsy+sK-iRFqDyTg2J*ldz<{5s$P2_O#G2A(yKof|LHK2_4*Mn=jP z5Pv?^!%H3T1waSX&9CE^*xytI0SoX==1NKs74%&hVr2(7w`{@9fccc^2!9z+1JnZZ zfO5b}A|1ng^5vjeGGqA*&DM!wSye{*4`eD&B~aplVdzcKK;ZFQq1xIe*^?Lx*IBx* zTdte*L(x4{8Jh4_M{|bmVf?4X~1~xk&xXIDn{Es;Hystf>zk_C!)eQ zQEin(!xh80gZ!hxMRR|UGl;YJgs9gYEKf~1kpkz`A5g(ZdeDaPN{IFcg`R3qYrGE;C zN5@TH{KZRG2WOhaX?=@I%N|=4zVQQiGUbBfrLWh^(*U0ygKGiMB=|J&Nf;UreSUUm z>=gw@3O>lrso;PCM{b#dTo&* zlb=xmn`V7hPnl`fS671>HBLWuJ^)4XR^QFk>fRPntyJr_raI> z>gR1X9JE2rbfw^hJ1(3B(K7?Uy1Oc#0kJ=a_;dF}JOkpJ4Dq%1R6GM>j}6aE=l>U8 z+sJ$y_4H8y001R)MObuXVRU6WV{&C-bY%cCFflVNFf%PPF;p=yIxsdmH8v|SGCD9Y z42|5^0000bbVXQnWMOn=I#q3NWNBu305UK!Gc7PPEi*AxF)%tXHaaynD=;!TFfe`4 zWNQEb02y>eSaefwW^{L9a%BK_cXuvnZfkR6VQ^(GZ*pgw?mQX*0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGf5&!@T5&_cPe*6Fc02*{fSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000NhNkl#u>-THd>|<6UrE3m6MT~lrbUW z8fSuUCUv1s zw{1SdbT#SqU)O21=K@+S`nGN75f23dxXjs1QZOF8O)TajKQvyQjavgm zZMxn5K8%JZ;PDKhpkN4A>uH!7A2#OH;&MX+pYw^}e;0{RCXw`y75T8BaRumgm43VZ z2po<<_llMZrZ;frk>n zZPGCnH)CTSzvFd3jRN-?B*h0{(61%nT|As&E51Re~N@Wk!iWXSpnfPP05<9}f zu}~<)MD}xx3HyM_ka^?$M=t|s58%!>yD{+DX52Xb683C)3NA-BW@%i|(scyB19JIU zNTuI_qE0{|T?vmU0l7lqxnF8>;|gf3%JXbnzZ7-Fv*C_cqiU`d?Hd;3TG#XF|K~;& zCQ8wqB0yte5OR!K#L{jkWDO9D4?`$CMb^8Zr5U#+lG50RN#6-!|a``GdblZJv2tc(FkMFC)NQjR2Imd~n8$M14BLSxbyA%80`5A0ySmG&T=8J>{0Y~uE&r2)?)R-G*nuq@wR)DX*d&2 zD7DPM{qSsB04e3Z6&m^mabX)mL!U!Lc;kRb=sp=1wp>1@fZREW?;hFFg1xV`V&IGI z_X_Smhd1z%bMQ-@Yw*gd0?dnacyv8cV zQ7NeKrgyAbl0P_H?GM5)?p+O^Qx87p*(TKa(r|ibE%F^SZ~HJjRVIL59(i!e$B=6r zX|oj9YYO7=4^r*-N6x`d?`lG3tdK7_ABnoAC>eiS=Y_`{IRfsG2%wckPuPaXY($)0 z6}A~@atPoep#59xc-uL6W2pmfs{|#cV7}Vxiyip*WgmPQCb;Mz-gYi>4sI6{0n*6t zrtAQ>AI8ji^XG@jyO%!Ku)6O#-2@!aQ2-iajLC)O!)B^=Hck3d>FKe zcNOxYA0<>-`(%WSNC7#5<}_V6oVrk0)zQ5M6_v~Vi95xd+OjZXfZg4UZ{DgO6*&jr zzkV(`6(vy0S0XH|8__e@+$R6W@1JxLa!u&xwmIqrQ#8lcaqz_oupQ0!a?aWQPHPb| z6LO$a*OM9G01uCd*oYJ=9d5b&;kEjoljA$Uo2)zghIA3I-2!HMzVH_Ix?1k{{dat VQyCYsUSt3O002ovPDHLkV1mx^^wiF4z3K4dw&I;Nklrc~H9LD(*%o5{U_h!kKWt&SR2#R8%+? z522A&;K+gfIDc2FLI9Jevnao z5lKb!L*Ri9*tzF32-v`h2xXEK2#=Rya1`hnoQA8rf$Y3e_%V3Oz@Ugwdz`ST2ss4o z>&qUPo z3t()D2pFHXy}9Roe|UGd4G@WD~U5Ft8{R6r;ku)SrcMa0FxQoMZt}e z({Rf27JqWEIp^lcXTxP}z>QYmI$77qx~c(0S9GBHhZ30!kNgD%Fc`t2qO&rLl87nz z6aD*YH|KnA@J`i)&5_TA zUups_lEvMeGO@m{1#-NSHesTy3HqEG^#59do=xY` zwXql-F~!g&Nziw&47yAS9&A2=#%(9insN%wNd>6ibQrSWY?OPZLlBh@SDNM1(n0_? zBwFzN@Lf}%8{3VTI;ey(;ToR*R*B)ba(|5caRY{8CG=-*WB61p1`BWC$+0RET)X28 z>N&?CXB>gd{~&Jq=b$b)7mBD{G{okhHY^h-IYQ9b(H55%3jzKCT&eM-76YW^UgWDS z-~+Lj@rW-mMc%XH61umaNBfpyXf}&YIajjtX5iI60#tb(K)J_$Tz21wi*9>x)_)}# zr+9@}?ah_WPJ@Mju*j{7@q$M5jQ}G@@6AL$8&28Y79oZv?9Z8kvjr|*nTQiV{tmB@ ztqQ9Ge2D|kM2*mqS#P%eQ^NB(qy`pqASgIm(3@F@b~4xdbL;Ub;iB(%AlEMo>sX7_ zfG4@n)udOT^Ns;Mq!`UP|5)28_~vboRAtu_~)>XQK%x_@Q=n^R%+ zKHx(SdVDKRifWP8rXgbup6-?m*R_ntcHIZ4FH?5W)&=NqZn=Ou?s3z2wKm}vgS)u; z=pDKdnMKf9k?O+ee7oWCzNuIp7^z+iZu9>FdQen6%P-Pc5S|AqJ!@vR&x@Rl+TFhC z@TBpKYZy`SAG(m*EWmt_n?5Itzt*3p3}wWQ#{HBrl^m3gBvu;uA!$=AKmMqjFHh-A fWASYPo4@lP1|UM4=tf9X00000NkvXXu0mjf%O%u+ delta 1773 zcmVauk_J%ZmSs5? z*aciz(B+6AA}W`lBF4(02~iHADi99QfI;Mnpj3(|5d;OKfCezAfGC0k!s1b@rqy&l zeU}an1d+o@|9EEinR(ym`+2^<<9XhBz`VH(x#9d2N2B>Y)_*$h^jT@Y6F-+V)bGqm zT>YYt#hYZf&tt!09*(+i_5NP~OeJ<^dWNEhR(8%RJCQD7E6fQ|m>|~G#7wGC=@^I} z8e7QBW&<-T2ON~%`97OI=j*DQM6Gh9B_o{b{h@eDjY%r+!aXnw3kTP%UkpIKu%(@I zZDi_kKJ&1nIe%|2HCeH^N(|Vt?--`GirU$T&p8LYLUyuBZpEJMAw+KpKyGc0Ye1B+ z-s}^4Rv{P@SQ)%S2*Vxfy5L+Vq@3vBV6>oOydX#u2)m8aKk+e1cW4~2CqzH58VxejQ&0d0NIatqD~^P)?T zeeoFyrv`{D=)fgt7bbRYr>ApcN`Ma*EO^sMY;`v}>kRql2e^3kKV0jF!3Qw>59l9( zjyupQw0|J=XcB;`1vk_n84W+Nv*Z@O@h8wWGQX={YbuZ_0W4&St7`G$`XSo7K_!Sj zd;;Br!tRCn>2@ejc&%NOvsal>uxjc^QqgSQ`_$IT3B=JV}eB@5dLM8FuDeNm9 z8h-`YS@8(>*m86&ol1Z1!XyAE&p=h~(aSV$${UTjs-TsBMO4zYI-4@H?UZiHrJ}t5 zMGh2KsyO7ANxHT#$0bo*Sf0!&yBIPJg4nS@L6jnzsE{1|S0`g`>vjK?03u5}v#-1p zXpqHmH@6v;>N(GkU*o5WP9CS#GqUw0b$^OP3XC>#aPeBwwR||Jvz`-@NG`gj(jJ;a zXG}ir5!qZ294NKfC4dAI|H&#s-<6^?UBjZK))P+42@Xi)?(rqAdl}yFEe|^$Fw*mw z=VjMM#h)B+HgVE*O3@W74_Xt0%K1`cWHdi+0&=p%mS9}3Yfd^>XkU?uiCV!W< zrBdUYNSWeG619Bs(o&*h=`!K+G6BHUMqYSg4f6)}9bGL{OrX!bAm z$5Z=L7MaKj$A@78fUS#n%_(s>gMUFq^tarjzqoT$d?2KRzQ7`S{POAYJ4)xqd^$Gd z((0ehrL~8sQ>IYmwC{y@sm*SVS$;u**$$3~!pSz;MuO%#JbtT(jn|lKaALqeORHPL`(Dv2Y)Oa+~N;A z?c(OTBV4Z<RX1m?Kpw20QuIx4%+MdxZ z44KVql^aj@6d-#PaDo zq0p}vtg-idnynW=yI&qB%kEJbS3j$S8!sOB(RviW*2YNJ@#&1t0<}ekmJWqq+JsRc z4x?dx-fM|_|K1F%KiZ+OR63#l$3ijXeZW{Gy%oLGU#Q{W8JF76cYm%Hw|-lUrjCVh zZ<@t@K>e`VE(1f$p$L6nl7)k&Toyap;a=8c)O9{yeD}gNc>Yc_Dz2ezGBl?f(F+KP zbK_dEFX8XY1(0>*inmYbaO1^eK3pS|n+*A{gip0U*`q0TYsjB|G<6D{?m{|afU$)Z z8{7CTFwo0LbSs%fEmB{{QFCpZ`ysIPt%@sOSbz&H&^H znmGWQE`M+h$mj5X!DR+SK3N&*7KFcRenDF1u)|PfrK!1wmR1X1CEvKpj$g!Mi z4j|WZsyKiW%PDpM%<|*MkN*c{u@4_UfN4-xLr?9vN?Wqa0c6YF-P}G$gonS~x^*i_ zmXjR<=#~SER@>a%TzM}~&l8Rg4j1h0>`=;ke02@UA%M+tN-8sw96)W$Ns0nmSWdJ9 zXk|H34xpvw1b-bsYs>LEfF73PbO609$LaujT8`lWdRva-fPt_a#Q~r;JE&FzRV<*g zos!~}6usc0I3+pRYx?x*|LyGTe$vx&cnE-kKQ1=*b5~avsKt7O6dzEk7G4>}#>CXL zG&ldRt*QBMWobz_N1)V(k&%&e%F4?A7v$&vH#0S*i&7&ns$*a$a!zJO#{Z*7ks>r{|ogsHkrN0RjJwjf|#H8qZ|4h)hjP>J0St?}8F2Egb*=2f$1v^&Q5X P00000NkvXXu0mjf+^gwo delta 469 zcmV;`0V@8>1jhuBe1En{L_t(oM`QT^|33q*v7&;4fTySDK{r>|3$89ME0FD@i{(B( zK6j2DJ^KIZ)vNy(ELia0-rjx}%n>wo0LbSs%kSU64|c%e!-xMD6&2kD${BzhK{E$n zvm6u(n>TO%pAa8^4=ArdGY8mYRR@q`In^9MuH{s5 z040`F>;RbMt5>i7f8f9Ya6X4+HT2YutF$G%96+|*(ZS)fzrX+6wQJY@U%!6+e_|~s zI|R@zx3{yiO-f9ZcX4(;VPj)+!P?pyrM$;i*N_|n*es`{G9$?W)V7?YD4>PqL_2_1 zmJ{UwT3Sxf0e`f%9IpfDVL46*(93eH4xp#y7!IJf)F93BFo;13B2`CL_5339{{QhY$ET6kp?928VjT2k`A zAV2@VxtST=9D!0B1_lPs$azwj{a|GU_f(6 zU~Lb$y1LE@4GsO~>*Mp^$k1>KrSVKwiwGD6b^3aGpiZO!Egb*=Vzf2XeRp5d00000 LNkvXXu0mjfS=8OE diff --git a/files/opencs/raster/random-item.png b/files/opencs/raster/random-item.png index 0b2571422cdf1f9e396129f80a800dabef387d88..7b8e68e60543867519ed7518d0061c8a21be3b60 100644 GIT binary patch delta 1594 zcmV-A2F3Zw526i_dw&KINklc2^rkbttJT4Abfl385<)_Ngb+x= z5)#8=2_T>#P(VZ~;BJvBt;L0cD6$q2M5z=gRZyxFMX0qbiW&mQCKgaD;B=mz@64PG zArO)aF21XioZs_q&wIX)0DNT0`FzzXfvdny8mJamM@Rakl7Ihdf+W`AA+jcarKmMH z(0xSi$!jq8ofg4EgQaz)mr{_E9fxsUHLAF+7Vc>fjLuFrtNOVGR` z0>U)Xk-4`I@!?%B{+k)a?DP{%k2d1X*gd>^-Hlhe8U(0BIx0&auZV!He!}L5_s-$p z*Ufl4eiQ!;Re#d(>9IB%o=0UyQ3*(73UB9OUGGIq43uJATa3}?g&6KD zz)YtmO!mI6`mi3}+kO_M7m^U{@ASut3!t*FD!}K{4@Z-&5E0Dz z;48D63kk5Fjn#YxrQ{P(&smm;u&4y&#ZrkQFF+}Hy?-;zV@|DbnDdp{&Z>Pmv!Ox4 zIfa}ziayNnvSTD*K(hQXc^=(>t9&|Qu{f6s=m+-Wi-(A~pa z5oTq8G@qZhbJyj<6if`(V``)w6T06p{-Ob6)ERwNkD;C_^mUv^SL-S4itw886g#Aw zBVt(r{(mZwdaJ^9^6&e3m>j-Koi?iZuA={O9-cq?5q+KK@TC0=dhTb_@W*$*!=pPV zabR!Ydxeajznln@0s_@;`FrBG&P)u{P_y1a&3y}oo)j+&?`%GShc`2E;$R2_j_ejw zB9;^&7IIoH<|I%NH{s3rBfRRbr|Nv3hPO3k;eT*?I0Dsj@OV6^m7Yk9^~bI2hrqxe zG-jZ!;TX#E;-Qf9JC<_CMFn_C`3;2npZdee4L89orVwhl^I076x`0v z4u7_`ws7Ryg%X}FXmjX~s6 z4_6#b3xz~1py6yb8=E$5!p<-+I&ucyRF#IC75h-06APi!=Fa&&VIV-Q6!tLvf`2!br=X!U8BrR^jKI-GZ&rE%6kL7bY&^AI zAJ8VlG~E1Aa}&AfYo2v%he5-oB?Z!OYinz4+_;fWI}3wi;b zVs6_&&t*)$ytgQv%=w+#W2h`jK}Eq{19;Q5gK%+n(8D*gS&PDN6egnPVgiB`&VM~j z8T108!o3E`sExh2ZuXoXKM;o9F)9Q2h7B7K8YrP_K0k5>el7niC}q4sBLPWqDlM_s zf$k!c4#&)SX>Ovv=1kfNoNe<3DyZ3C3VxL;!8V0JYb0QItWrz7-ITq~H<{v`c!QcV z@WLOWO~Na4b|J`j5dn!YO6};g+J7azeWAk@o{iJjoWP^Q({SGPG*Ez@bc^(2=L|`mw@`v=zQ_lC2FPS8Em!1 z;KXEptw=?Hp9o%_PEh%{pytwUdd|tH&2KnTbCPxvIf0j*iiDdJyVa-%WPcLJ^s3^o z@w~G@zfzZiGY*$~at9K3`rvHFcC+CpQq)9%eogDgka%>|cKP(v2f6e(f0SvK;LtZ=BL-0AuIz`%eZ`}wSSvQc;3-q@U~bR-5ZS7 zF-ea^Xy2K6Kx4F07kWEMJBfTbIEh@yvoTu5CNCx;XS)cwgxi;zphEGP7?a+*PT^4;2&94!;ho%oJr@xP2FjOtnYSgaUU^5kUlrGvY{hYPL sUWvmIlOc0XMoq-GsdlupHhE9@AL3)&a$Qp|g8%>k07*qoM6N<$f{UXW8UO$Q delta 1891 zcmV-p2b}n#4apCXdw&NwNkl@9t3Xn!<5TQV@Sp;NhQ4m>_0@RU4QCzXLr6a@OP0{b*IQg36d>zW%76Hg^t0q|f6%R!p9%Dp z^tvmB4|D-Cqt;WDWzYB84OhzflE^R(67~e)WJxrxUdq71#9$EU1N}O=v9=->z3pje zYuJZ`UF)Fr_+JMg;}2dupNa`XHJ*=F;q6ot#vfJSdjApJ8!W)YXeGu*P9W#-CMcx5 zE_>9|_t>3*5PzLALLa2~czYm^f&csCbC}-V#k=W$;LT(|UXY+Jcc#O~%XPwD_@V-! zZ}w0LQ&0f71DJO+KFNkL&$iOj-}&dxeBs|9=TU zF6Buy9-?0|lE1~(?hIVJl!>mEWTp%kniA2`d;piur6TP>FeGm5u}yl_pX~``!3J1!PEPdFx;!cFSkl@vo8lf6h%QPxm&ukN4x{(>_d&cH#NsHar{o5u?K= z@!;C`81BzSbLDPq&?!wyDX(R|AZ!NkS+z^wu74Q+5B(j7VI+q0%6Ngy|1f5r50aTb zM--Q0^iBy;U5rOVMR+(^$iVMj&BN`>xwzGvgZ9%2NQe!DtH9|A{Z3nfd=&t3F$qcC zSVeI(<8agCO$2-c?_S;|LG;1+b0u!{HYXuJeG?7ht(QuuogIW#0PEMvwZz+}J6n=4_OKi?6W#dNs}V-|#Aq{Pwbdu~ z!^=wzsZ`3q#bPmBU0op(i6E1TQS@Cj%RV(}wf(R9Vta;XhqGVyU@@TEf8DY&KkkJe%;Yy8Y-l6_1MCNNALTH}tk( zkuh`L7NIqb+&qTYFM1f|w&1keJ=~R+n&)M1w`#bQ_zeu)+1VLRPEMAzo0Xg4?Nxhl zwmcSzF@BJXIkha6oZt21sl9kPR)5bZe`W0YO1XK|u5@JKO!WaYRV7%#`_837rEs&r z`8+mLb6fDXle=(^1W-UWr_7E0fVIwF`h?mlo%1)7LvzAy&3X2raO~Nkvw}N1IwEX? zW?pzp*-ji!4~0auYJwFS;%*q~&ta5Pdo?%QLMBsNw%by3bJ{7K$6bZSvVS|YH^Zw6V-|!r9*;s%+Q!cT zY}Bg^13g)cz0$?9kaDxhR2RouYEI$N5xzKIv(GO0>B4QuPY!`X%rUY8*GQhwTkhG< zrc;5`Lq+(9w-W>tBNml5S z;WC?BZ8qHOaHU7LVRuv@j%ROK6udk$6d`^R@YxP2%r0&a`3HAIyFPR&cvcFoXvlk0ZJ5^5MOP4N1Ug}21 z;mmVxOL@*d9oA{w;D5q(v|LG6_W;R6966z8j*_2OjpcFZBxW+#R--0E(@vEy1gAAm z-Qf=}Ip4He=v?sSQS#MA#GGR)VXaEa8{15Fck-^aDE%%1Ww~2$>Ua!ljzyvB`|bE4 ze=D=qP8^9qX?7S&$PX22ug8eN6dc@uTyh;BCZCPp>diEqfL!A+MU?C3y@+Q2ldemp zgquaO(m`Ht`Fgn;Je30D8V`}dhdkbD7lT$UG-y>q16i*IFNMHB-HjTITEcxu$BaBJ dw!miAe*lrQqikNLH*f#|002ovPDHLkV1i|owQ>Le diff --git a/files/opencs/raster/repair.png b/files/opencs/raster/repair.png index 5e495d8fd72c88a04aab96c5eb72ad11fb5ad9e4..6cf1c0aacd2fbb94db16cdf30f0008d8c69e08db 100644 GIT binary patch delta 1036 zcmV+n1oQiV3fl;fB#|)~3K0MR3lRZ-WM7eyQz(A}*GWV{R9HvtS4mHsR}}S6$Ui9E zr`d!`3BfgXWtzlbX5(VO#x^b#%oOGsf}wzjC?F(2Kp==wh*2PdKm>sZNK8UvgCae- zU36Eesj9S_(|e!dDy3kX#1UO&@fQBR_uX^ubndkRfZ{sOwSu$bp9oxk1fukMx6Nu5 zX%>HrFsG)9l;mV#N=gzB?%#i%Znq1&%_jK0H7!lvv6#*BUh3Ps$tII9(Mh6jzBL+! zkxrt)APfl!B7shPe7uN@jTNzUVq#)Mbab?cii#3?yR%MPhYx=}J3GV4$q9~+ zk8yZ-i2eP2l$Mm>=;#Os2M6-^-rgQ|cXxlWv$KQk?QLvrZDDhB6B`>FSYKbq+S(dc zS68vJvV!I1Wh^Z%VR3O03kwUFo14ST%nYWdr!h4(g~`cDjE|4Qk)9647dLOZ8Gt|F zi+qV+lE)I94SI~t&(C9acJ?1b6B82{8ymyO$OwjqhcP%fi2nY5^!4?jr>6(q-Q9oa z>gqyAM+e&5+tJq6hSt_rG&eV+u&@weDisvLw{M$T=m7(tC*UE*o&*BCy1E*1adB@n z8qMj~8coONK|w*X2z5H0QKMG7Gcz)zH=YP^*aHFH*w_fIR{NTq-3ki}yY;T{{i_S8 z@Qf4|cTrK1OabToLp{&R%0lS9d#8WubHE-F7q(%zR%=u$mA`YreMru!d;Us}`KyZbwK+NVTsypS($7VE}pAYdreIZhy8^waKC2(MZ@t; zc(|Jj)Sp(1(CL1o3cnFB0&K`^HhxxoX$Ua$Z+^C(smDceSJOZ>gqt#@289GoG135HndnQct(R|XlO`Q{J_9~ zlw$_xA>#|2Td=maR^ILH?L~jX}-6WnTZUVq~AFlU1+*=JHYFGg1~A5@(=c>0BH|^tSZ8M^ zexwEB2`>;WE%s+|lEciTIK(BiHF1dZ^Yg)EvWZM4k#P_ao6QDV;gCuMXvKpu zF%h()fieES1UNh&dlB`T0)NFLkoT_te?cI zudlDgjdU{Ik?tku*tE;Qz=;-*TpP!%Pr&38O`k$Zi_3@E>=WbaIlM=qMBlNp5fdy9GV`$H~bFE-x=} zadCmOvoq}P?;|=Y3QJ2%I6ptf>FFtskB@P9c!-081MKbXVSi_52U}ZP*x1;>+S(dc zR#wFGi;IhxpP$F<>@23Ir!hG>iShAqjE;_Ccz76tgM;Yr??+cx7lML_jo12^9XZio-<>hOznVA_(O-%`~v9U3XjEo4Nfq?<^ z_4T2*w--G_kUL2U=QMP+VLLQUew;nJh9dFAoa~3!)%1=VDQjkphG}H|}n3 zZVn7+=#0UJhK6o{b$53Qu(q}~w6?aQxw#pQjg8Qkl_6B4`6QRi-#N(Ttv^^=T8bf5 zynLypJGv@;^G0;Ql0`;D2uWFXgS7Vruc)X%KtRCXvVZ5#5AE&jtc`>3h6{dr@j^>v zu2>#TNQh8`uZDl`3!a&o30oVRcQkM}fDI(RYC{JH2Q9tyfrp9j|Gwby@$nz2<6mxz zdXqUoFZS~+9335r!$ZhZeb+lDaM)N|>&@+%TM4ig6A}_oSy?Hp#n&-0F=2M#N=r*w z_I-2UcYodmq=t?{<%<2wN*JtVYT7BBKG1}J_h1CL5T)PuTCMgkwj|rmq}B9#SX)_b z+y(s33K)t}l)mMh;E?&6&+F^!k)ECoit(gJA>gD?T=5`s!hIex3|?DXi?p;f*xB0V zJ~#nNF0D?d`@~nk@*5|d0lcQB2Ib}DpuqX*3+y;M$)P`hq}obhOxdya`uVSH(hNaPHn*=M2snP)19Kmk$pruU#h7-rf$b zZGV=4VGZ*NHDxtZoijMA#+?@w6o9uZUq@C}7BVt2gc`RJpsyPL5L!Y!Ok5y8KOecd zxyZ@R7Dafmu+36aQ<0+6At@;diHV7bkBdWWY^>-olGZrOtqlu9XlN)j8V%I1ULiO* z7+jk%Om0K6*(qCzrEY3!LPJ9X>gwtQp?|8XD)3t6`QR>#ii)ng%qD_NjxET<1S#4D zG5-;w025@?YBlH!?1luCqb?>` P00000NkvXXu0mjf{DwyH diff --git a/files/opencs/raster/weapon.png b/files/opencs/raster/weapon.png index b68878a54abbadce500135ea0dd77e7e53168118..3d4b534661076843ba4db3fa81c056d44e108cb2 100644 GIT binary patch delta 892 zcmV-?1B3ji226mGcx(sEIm65g?=zpA60SIm~nZWDy!pzJJsH&^C zn(J|D)U2-?;f}5dFb>laY~dZa2Lj>K)6-zJTA@-d-)c~c!2F^P#-FRepy30?PV-L( zEeTvusfM;Y_rWJ7CSYuA3@Qj>t5%T@Z~Nt7d`wVtAGjy>oj_A#WB=&rs6X~VxY1~Y z-riow$$#dqT(8C8Wp^p?ILGaQW!RShGTyrgzOk_Zv$L}h46fJffy?1gbthem$*Tt~ zs{;$baojL6GUDAUJlvl)q6859+2G(hUGRt&5rW_D==dEDUQ%2<6wdYb=X*+EuW*7O z`XhnwDFK~UD+}jb+tT7G6bkP~3J)s)!P{C}$$tgs4cYC@&CS1fJf2}c@LdIn3JWnG z+~IHp9kufE^7VtjLkd7}GFBIIJ~uZPHF!_~2u^OfZ?S;y5P;y4ii$Ol#}m@IQlaox zDV4JQ);#1U{2y?C0yo;*8RVbs`)$bMJwzC~g8kO*MPy}%<;wSyJmZstM`E*dSB;<&=YZ3vchrGk4 zfJgJ68{u|#p?|&62$fu5CvZM5`JYL{gT=^)Hai(SPU31x@)1=~Ae#bA&36s>`Sl^@ zJ~iV(offj})V2FHC(wB_12x7(q;d`~Z-ld&0J$t*Df?4%QG+iZ?qS;AfQB1ND05OH zI%hornN(`;>gqy8dHH&kS%s;$x8ZnGi(8ka$U4bg3x9XcssIANQ(uqS*;yC^wAbfgy8Y?R+n3+3^dp>e%PE5SfVF`hRY19Km~ zC-$5GO@Gr*qrrQ7d(qzB4y)A)iCFZRv#?hB4ku>fFzO4YILZONUS11(z{lKFN zAn;O}c5UaJ4R}NW1kSA3-|>KN5kTO~@sfS+cDoU&=BL$aA2St}z1BSHCJe&KhlF%` zJb&P!1TIxo9n)#Go*>-o^=|3*e3i;2&d3P;%dwUKfs>j?gSWM{K`xX1J_vXqfdZY* zF*rCFh&|kSOG^uwG4mc2JRpFgsCT2IqwshMl+*1##W Date: Sun, 14 Apr 2013 17:04:55 +0200 Subject: [PATCH 0421/1537] added basic cell table --- apps/opencs/CMakeLists.txt | 2 +- apps/opencs/model/world/cell.cpp | 20 ++++++++++++++++++++ apps/opencs/model/world/cell.hpp | 17 +++++++++++++++++ apps/opencs/model/world/data.cpp | 17 +++++++++++++++++ apps/opencs/model/world/data.hpp | 6 ++++++ apps/opencs/model/world/idcollection.hpp | 6 ++++-- apps/opencs/model/world/universalid.cpp | 2 ++ apps/opencs/model/world/universalid.hpp | 4 +++- apps/opencs/view/doc/view.cpp | 9 +++++++++ apps/opencs/view/doc/view.hpp | 2 ++ apps/opencs/view/world/subviews.cpp | 1 + components/esm/loadcell.cpp | 18 ++++++++++++++++++ components/esm/loadcell.hpp | 3 +++ 13 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 apps/opencs/model/world/cell.cpp create mode 100644 apps/opencs/model/world/cell.hpp diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 5c15938bda..efc3551fd3 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -22,7 +22,7 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase scriptcontext + universalid data record idcollection commands columnbase scriptcontext cell ) opencs_hdrs_noqt (model/world diff --git a/apps/opencs/model/world/cell.cpp b/apps/opencs/model/world/cell.cpp new file mode 100644 index 0000000000..759468fa8f --- /dev/null +++ b/apps/opencs/model/world/cell.cpp @@ -0,0 +1,20 @@ + +#include "cell.hpp" + +#include + +void CSMWorld::Cell::load (ESM::ESMReader &esm) +{ + mName = mId; + + ESM::Cell::load (esm, true); /// \todo set this to false, once the bug in ESM::Cell::load is fixed + + if (!(mData.mFlags & Interior)) + { + std::ostringstream stream; + + stream << "#" << mData.mX << " " << mData.mY; + + mId = stream.str(); + } +} \ No newline at end of file diff --git a/apps/opencs/model/world/cell.hpp b/apps/opencs/model/world/cell.hpp new file mode 100644 index 0000000000..6a9676a559 --- /dev/null +++ b/apps/opencs/model/world/cell.hpp @@ -0,0 +1,17 @@ +#ifndef CSM_WOLRD_CELL_H +#define CSM_WOLRD_CELL_H + +#include + +namespace CSMWorld +{ + /// \brief Wrapper for Cell record + struct Cell : public ESM::Cell + { + std::string mId; + + void load (ESM::ESMReader &esm); + }; +} + +#endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 9f6b186c0c..83702b05c6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -119,6 +119,11 @@ CSMWorld::Data::Data() mSpells.addColumn (new FlagColumn ("Starter Spell", 0x2)); mSpells.addColumn (new FlagColumn ("Always Succeeds", 0x4)); + mCells.addColumn (new StringIdColumn); + mCells.addColumn (new RecordStateColumn); + mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); + mCells.addColumn (new NameColumn); + addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill); @@ -130,6 +135,7 @@ CSMWorld::Data::Data() addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); + addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell); } CSMWorld::Data::~Data() @@ -248,6 +254,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getSpells() return mSpells; } +const CSMWorld::IdCollection& CSMWorld::Data::getCells() const +{ + return mCells; +} + +CSMWorld::IdCollection& CSMWorld::Data::getCells() +{ + return mCells; +} + QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map::iterator iter = mModelIndex.find (id.getType()); @@ -293,6 +309,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base) case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; case ESM::REC_SPEL: mSpells.load (reader, base); break; + case ESM::REC_CELL: mCells.load (reader, base); break; default: diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index d7b69ba5e3..03a2448f11 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -20,6 +20,7 @@ #include "idcollection.hpp" #include "universalid.hpp" +#include "cell.hpp" class QAbstractItemModel; @@ -38,6 +39,7 @@ namespace CSMWorld IdCollection mRegions; IdCollection mBirthsigns; IdCollection mSpells; + IdCollection mCells; std::vector mModels; std::map mModelIndex; @@ -98,6 +100,10 @@ namespace CSMWorld IdCollection& getSpells(); + const IdCollection& getCells() const; + + IdCollection& getCells(); + QAbstractItemModel *getTableModel (const UniversalId& id); ///< If no table model is available for \a id, an exception is thrown. /// diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 3bf53349e6..4afe9cbaab 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -325,10 +325,10 @@ namespace CSMWorld { std::string id = reader.getHNOString ("NAME"); - int index = searchId (id); - if (reader.isNextSub ("DELE")) { + int index = searchId (id); + reader.skipRecord(); if (index==-1) @@ -354,6 +354,8 @@ namespace CSMWorld record.mId = id; record.load (reader); + int index = searchId (record.mId); + if (index==-1) { // new record diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 11f4877886..c0241bc383 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -28,6 +28,7 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -45,6 +46,7 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 5586b22e79..9b52aded1f 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -55,7 +55,9 @@ namespace CSMWorld Type_Birthsigns, Type_Birthsign, Type_Spells, - Type_Spell + Type_Spell, + Type_Cells, + Type_Cell }; private: diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index dfdcb10365..a684b85c5b 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -125,6 +125,10 @@ void CSVDoc::View::setupWorldMenu() QAction *spells = new QAction (tr ("Spells"), this); connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView())); world->addAction (spells); + + QAction *cells = new QAction (tr ("Cells"), this); + connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView())); + world->addAction (cells); } void CSVDoc::View::setupUi() @@ -325,6 +329,11 @@ void CSVDoc::View::addSpellsSubView() addSubView (CSMWorld::UniversalId::Type_Spells); } +void CSVDoc::View::addCellsSubView() +{ + addSubView (CSMWorld::UniversalId::Type_Cells); +} + void CSVDoc::View::abortOperation (int type) { mDocument->abortOperation (type); diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 9241efbb9a..a240d3b01d 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -133,6 +133,8 @@ namespace CSVDoc void addBirthsignsSubView(); void addSpellsSubView(); + + void addCellsSubView(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 8f7887f3b9..0ce3d3d6db 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -26,6 +26,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, + CSMWorld::UniversalId::Type_Cells, CSMWorld::UniversalId::Type_None // end marker }; diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 5cbf1de2b7..77e4d3691c 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -356,4 +356,22 @@ bool Cell::getNextMVRF(ESMReader &esm, MovedCellRef &mref) return true; } + void Cell::blank() + { + mName.clear(); + mRegion.clear(); + mWater = 0; + mWaterInt = false; + mMapColor = 0; + mNAM0 = 0; + + mData.mFlags = 0; + mData.mX = 0; + mData.mY = 0; + + mAmbi.mAmbient = 0; + mAmbi.mSunlight = 0; + mAmbi.mFog = 0; + mAmbi.mFogDensity = 0; + } } diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index 44412b5eb9..d7f64817f8 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -140,6 +140,9 @@ struct Cell * Since they are comparably rare, we use a separate method for this. */ static bool getNextMVRF(ESMReader &esm, MovedCellRef &mref); + + void blank(); + ///< Set record to default state (does not touch the ID/index). }; } #endif From 71148121a2d5327156d16fb0ceb779117cc90a96 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 17:10:37 +0200 Subject: [PATCH 0422/1537] added flag columns to cell table --- apps/opencs/model/world/data.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 83702b05c6..604b55109d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -123,6 +123,9 @@ CSMWorld::Data::Data() mCells.addColumn (new RecordStateColumn); mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); + mCells.addColumn (new FlagColumn ("Sleep forbidden", ESM::Cell::NoSleep)); + mCells.addColumn (new FlagColumn ("Interior Water", ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn ("Interior Sky", ESM::Cell::QuasiEx)); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 48f46e505cb9a1a1e7adde097ba1c69132eee54b Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Apr 2013 17:37:39 +0200 Subject: [PATCH 0423/1537] Look in exterior cells first (chargen_crate_01_empty is in the prison ship but also outside of it, the one outside needs to be disabled) --- apps/openmw/mwworld/cells.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 4838cfefa5..87ac1c6d7f 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -165,6 +165,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, Ptr::CellStore& ce else return Ptr(); } + MWWorld::Ptr ptr; if (MWWorld::LiveCellRef *ref = cell.mActivators.find (name)) @@ -246,16 +247,16 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) } // Then check cells that are already listed - for (std::map::iterator iter = mInteriors.begin(); - iter!=mInteriors.end(); ++iter) + for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); + iter!=mExteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) - return ptr; + return ptr; } - for (std::map, Ptr::CellStore>::iterator iter = mExteriors.begin(); - iter!=mExteriors.end(); ++iter) + for (std::map::iterator iter = mInteriors.begin(); + iter!=mInteriors.end(); ++iter) { Ptr ptr = getPtrAndCache (name, iter->second); if (!ptr.isEmpty()) @@ -266,7 +267,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) const MWWorld::Store &cells = mStore.get(); MWWorld::Store::iterator iter; - for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) + for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) { Ptr::CellStore *cellStore = getCellStore (&(*iter)); @@ -276,7 +277,7 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name) return ptr; } - for (iter = cells.extBegin(); iter != cells.extEnd(); ++iter) + for (iter = cells.intBegin(); iter != cells.intEnd(); ++iter) { Ptr::CellStore *cellStore = getCellStore (&(*iter)); From a57fbbb168a68201b22b63f218397e2758d2de22 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 14 Apr 2013 17:51:17 +0200 Subject: [PATCH 0424/1537] Fix wrong detection of diseases --- apps/openmw/mwmechanics/spells.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index e2da7cdc86..e10dcdc93d 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -80,7 +80,7 @@ namespace MWMechanics const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - if (spell->mData.mFlags & ESM::Spell::ST_Disease) + if (spell->mData.mType == ESM::Spell::ST_Disease) return true; } @@ -94,7 +94,7 @@ namespace MWMechanics const ESM::Spell *spell = MWBase::Environment::get().getWorld()->getStore().get().find (iter->first); - if (spell->mData.mFlags & ESM::Spell::ST_Blight) + if (spell->mData.mType == ESM::Spell::ST_Blight) return true; } From b2b953d2a88d844c35ef58b3b5303d12d8541b48 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 14 Apr 2013 19:34:55 +0200 Subject: [PATCH 0425/1537] added region column to cell table --- apps/opencs/model/world/columns.hpp | 25 +++++++++++++++++++++++++ apps/opencs/model/world/data.cpp | 1 + 2 files changed, 26 insertions(+) diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 9242e8a23b..f1d8d4ae62 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -748,6 +748,31 @@ namespace CSMWorld return true; } }; + + template + struct RegionColumn : public Column + { + RegionColumn() : Column ("Region", ColumnBase::Display_String) {} + + virtual QVariant get (const Record& record) const + { + return QString::fromUtf8 (record.get().mRegion.c_str()); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mRegion = data.toString().toUtf8().constData(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + }; } #endif \ No newline at end of file diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 604b55109d..dedbfc4e7d 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -126,6 +126,7 @@ CSMWorld::Data::Data() mCells.addColumn (new FlagColumn ("Sleep forbidden", ESM::Cell::NoSleep)); mCells.addColumn (new FlagColumn ("Interior Water", ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn ("Interior Sky", ESM::Cell::QuasiEx)); + mCells.addColumn (new RegionColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); From 4e0233cf06384472ef49f47de87fcccc1068066c Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 14 Apr 2013 21:42:37 +0200 Subject: [PATCH 0426/1537] Base local rotations implementation --- .../mwscript/transformationextensions.cpp | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6c4fb0f4bd..922353974d 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -553,26 +553,30 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why + Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) runtime.pop(); - float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); - float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); - float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees(); + float *objRot = ptr.getRefData().getPosition().rot; - //Axis in morrowind are inverted - if (axis == "y") + if (axis == "x") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + objRot[0]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; } - else if (axis == "x") + else if (axis == "y") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + objRot[1]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); } else if (axis == "z") { - MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + objRot[2]+=Ogre::Degree(rotation).valueRadians(); + + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); } + else throw std::runtime_error ("invalid rotation axis: " + axis); } From bf8bc989fc0184f59aa40f9d3a028d4fad6f749b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 12:52:20 -0700 Subject: [PATCH 0427/1537] Recognize and partly handle NiBSParticleNode --- components/nif/niffile.cpp | 2 +- components/nif/record.hpp | 1 + components/nifogre/ogrenifloader.cpp | 12 +++++++----- components/nifogre/skeleton.cpp | 1 + 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 3b41e96a70..2c4f3506ea 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -208,7 +208,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiNode", &construct , RC_NiNode }, { "AvoidNode", &construct , RC_NiNode }, - { "NiBSParticleNode", &construct , RC_NiNode }, + { "NiBSParticleNode", &construct , RC_NiBSParticleNode }, { "NiBSAnimationNode", &construct , RC_NiBSAnimationNode }, { "NiBillboardNode", &construct , RC_NiNode }, { "NiTriShape", &construct , RC_NiTriShape }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 361af3f64c..97b10503e8 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -39,6 +39,7 @@ enum RecordType RC_NiTriShape, RC_NiRotatingParticles, RC_NiAutoNormalParticles, + RC_NiBSParticleNode, RC_NiCamera, RC_NiTexturingProperty, RC_NiMaterialProperty, diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 631d397283..1ed5e24a36 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -469,7 +469,7 @@ class NIFObjectLoader static void createParticleSystem(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, ObjectList &objectlist, - const Nif::Node *partnode, int flags, int animflags) + const Nif::Node *partnode, int flags, int partflags) { const Nif::NiAutoNormalParticlesData *particledata = NULL; if(partnode->recType == Nif::RC_NiAutoNormalParticles) @@ -539,7 +539,7 @@ class NIFObjectLoader static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, - ObjectList &objectlist, int flags, int animflags) + ObjectList &objectlist, int flags, int animflags, int partflags) { // Do not create objects for the collision shape (includes all children) if(node->recType == Nif::RC_RootCollisionNode) @@ -552,6 +552,8 @@ class NIFObjectLoader if(node->recType == Nif::RC_NiBSAnimationNode) animflags |= node->flags; + else if(node->recType == Nif::RC_NiBSParticleNode) + partflags |= node->flags; else flags |= node->flags; @@ -622,7 +624,7 @@ class NIFObjectLoader if((node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles) && !(flags&0x40000000)) { - createParticleSystem(name, group, sceneMgr, objectlist, node, flags, animflags); + createParticleSystem(name, group, sceneMgr, objectlist, node, flags, partflags); } const Nif::NiNode *ninode = dynamic_cast(node); @@ -632,7 +634,7 @@ class NIFObjectLoader for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags); + createObjects(name, group, sceneMgr, children[i].getPtr(), objectlist, flags, animflags, partflags); } } } @@ -679,7 +681,7 @@ public: // Create a base skeleton entity if this NIF needs one createSkelBase(name, group, sceneMgr, node, objectlist); } - createObjects(name, group, sceneMgr, node, objectlist, flags, 0); + createObjects(name, group, sceneMgr, node, objectlist, flags, 0, 0); } }; diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 28df4894db..75bc907152 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -165,6 +165,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, node->recType == Nif::RC_RootCollisionNode || /* handled in nifbullet (hopefully) */ node->recType == Nif::RC_NiTriShape || /* Handled in the mesh loader */ node->recType == Nif::RC_NiBSAnimationNode || /* Handled in the object loader */ + node->recType == Nif::RC_NiBSParticleNode || node->recType == Nif::RC_NiCamera || node->recType == Nif::RC_NiAutoNormalParticles || node->recType == Nif::RC_NiRotatingParticles From 7000a1aa3eba373f33741e7f208e1af8bd6c45e7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 13:50:55 -0700 Subject: [PATCH 0428/1537] Add a ParticleSystemController --- components/nifogre/ogrenifloader.cpp | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 1ed5e24a36..69f14b663d 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -329,6 +329,35 @@ public: typedef DefaultFunction Function; }; +class ParticleSystemController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::ParticleSystem *mParticleSys; + float mEmitStart; + float mEmitStop; + + public: + Value(Ogre::ParticleSystem *psys, const Nif::NiParticleSystemController *pctrl) + : mParticleSys(psys) + , mEmitStart(pctrl->startTime) + , mEmitStop(pctrl->stopTime) + { + } + + Ogre::Real getValue() const + { return 0.0f; } + + void setValue(Ogre::Real value) + { + mParticleSys->setEmitting(value >= mEmitStart && value < mEmitStop); + } + }; + + typedef DefaultFunction Function; +}; /** Object creator for NIFs. This is the main class responsible for creating @@ -521,6 +550,13 @@ class NIFObjectLoader Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } + + Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } ctrl = ctrl->next; } From f9dee25fd1c0218fd40ac11e2b3406bbb70283b5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 16:56:35 -0700 Subject: [PATCH 0429/1537] Store the base skeleton entity in MWRender::Animation --- apps/openmw/mwrender/animation.cpp | 21 ++++++++++++--------- apps/openmw/mwrender/animation.hpp | 3 ++- apps/openmw/mwrender/npcanimation.cpp | 5 ++--- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a849b20efe..d6f762ab76 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -33,6 +33,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) , mController(NULL) , mInsert(NULL) + , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) , mAccumulate(Ogre::Vector3::ZERO) @@ -65,7 +66,7 @@ Animation::~Animation() void Animation::setAnimationSources(const std::vector &names) { - if(!mObjectList.mSkelBase) + if(!mSkelBase) return; Ogre::SceneManager *sceneMgr = mInsert->getCreator(); @@ -81,7 +82,7 @@ void Animation::setAnimationSources(const std::vector &names) mAnimationSources.clear(); Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); std::vector::const_iterator nameiter; for(nameiter = names.begin();nameiter != names.end();nameiter++) { @@ -127,7 +128,7 @@ void Animation::setAnimationSources(const std::vector &names) if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mObjectList.mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } for(int i = 0;i < skel->getNumAnimations();i++) @@ -152,7 +153,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model mObjectList = NifOgre::Loader::createObjects(mInsert, model); if(mObjectList.mSkelBase) { - Ogre::AnimationStateSet *aset = mObjectList.mSkelBase->getAllAnimationStates(); + mSkelBase = mObjectList.mSkelBase; + + Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -164,7 +167,7 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); @@ -182,9 +185,9 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model Ogre::Node *Animation::getNode(const std::string &name) { - if(mObjectList.mSkelBase) + if(mSkelBase) { - Ogre::SkeletonInstance *skel = mObjectList.mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skel = mSkelBase->getSkeleton(); if(skel->hasBone(name)) return skel->getBone(name); } @@ -508,11 +511,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) for(size_t i = 0;i < mCurrentControllers->size();i++) (*mCurrentControllers)[i].update(); - if(mObjectList.mSkelBase) + if(mSkelBase) { // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. - mObjectList.mSkelBase->getAllAnimationStates()->_notifyDirty(); + mSkelBase->getAllAnimationStates()->_notifyDirty(); } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 029c56523d..32344a2c02 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -42,7 +42,8 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; - Ogre::SceneNode* mInsert; + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; NifOgre::ObjectList mObjectList; std::map mTextKeys; Ogre::Node *mAccumRoot; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d0..a2446b8671 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -359,8 +359,7 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { - NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mObjectList.mSkelBase, bonename, - mInsert, model); + NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); for(size_t i = 0;i < objects.mEntities.size();i++) { objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); @@ -408,7 +407,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mObjectList.mSkelBase->getSkeleton(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; From 2693b785362ec30ba729c7807ad20d7a0d2d74f7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Apr 2013 02:56:23 +0200 Subject: [PATCH 0430/1537] Add initial player inventory when new game is started --- apps/openmw/engine.cpp | 1 + apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwclass/armor.cpp | 19 +++++++----------- apps/openmw/mwclass/armor.hpp | 5 +++-- apps/openmw/mwclass/clothing.cpp | 20 ++++--------------- apps/openmw/mwclass/clothing.hpp | 3 ++- apps/openmw/mwclass/weapon.cpp | 8 ++++---- apps/openmw/mwclass/weapon.hpp | 3 ++- .../mwmechanics/mechanicsmanagerimp.cpp | 12 +++++++++++ apps/openmw/mwworld/actionequip.cpp | 10 +++++++--- apps/openmw/mwworld/class.cpp | 4 ++-- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/inventorystore.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 16 ++++++++++++--- apps/openmw/mwworld/worldimp.hpp | 1 + 15 files changed, 62 insertions(+), 46 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 69e3cdc534..4472b205f7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -368,6 +368,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mMaster, mPlugins, mResDir, mCfgMgr.getCachePath(), mNewGame, mEncoder, mFallbackMap, mActivationDistanceOverride)); + MWBase::Environment::get().getWorld()->setupPlayer(mNewGame); //Load translation data mTranslationDataStorage.setEncoder(mEncoder); diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890a..bee744386f 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -321,6 +321,7 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 0; + virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 6791138d35..8a8f72c888 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -292,7 +292,7 @@ namespace MWClass ref->mBase = record; } - int Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Armor::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { MWWorld::InventoryStore& invStore = MWWorld::Class::get(npc).getInventoryStore(npc); @@ -317,10 +317,7 @@ namespace MWClass { if((*itr).mPart == ESM::PRT_Head) { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - return 0; + return std::make_pair(0, "#{sNotifyMessage13}"); } } } @@ -331,9 +328,7 @@ namespace MWClass { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage14}"); - return 0; + return std::make_pair(0, "#{sNotifyMessage14}"); } } } @@ -344,7 +339,7 @@ namespace MWClass MWWorld::ContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(weapon == invStore.end()) - return 1; + return std::make_pair(1,""); if(weapon->get()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand || weapon->get()->mBase->mData.mType == ESM::Weapon::BluntTwoClose || @@ -354,12 +349,12 @@ namespace MWClass weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || weapon->get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - return 3; + return std::make_pair(3,""); } - return 1; + return std::make_pair(1,""); } } - return 1; + return std::make_pair(1,""); } boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 703d3af1ed..9b8e9dd149 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -67,8 +67,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; - ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. \n + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index 6c231e0c60..3072f852d5 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -238,7 +238,7 @@ namespace MWClass ref->mBase = record; } - int Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Clothing::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { // slots that this item can be equipped in std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -260,12 +260,7 @@ namespace MWClass for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_Head) - { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage13}"); - - return 0; - } + return std::make_pair(0, "#{sNotifyMessage13}"); } } @@ -274,19 +269,12 @@ namespace MWClass for(std::vector::iterator itr = parts.begin(); itr != parts.end(); ++itr) { if((*itr).mPart == ESM::PRT_LFoot || (*itr).mPart == ESM::PRT_RFoot) - { - if(npc == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage15}"); - } - - return 0; - } + return std::make_pair(0, "#{sNotifyMessage15}"); } } } } - return 1; + return std::make_pair (1, ""); } boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 1be42adbd4..a6de0cb4f0 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -61,8 +61,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index fbac6d89e8..6c6b3daa61 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -384,7 +384,7 @@ namespace MWClass ref->mBase = record; } - int Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Weapon::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { std::pair, bool> slots = MWWorld::Class::get(ptr).getEquipmentSlots(ptr); @@ -402,12 +402,12 @@ namespace MWClass ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanBow || ptr.get()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow) { - return 2; + return std::make_pair (2, ""); } - return 1; + return std::make_pair (1, ""); } } - return 0; + return std::make_pair (0, ""); } boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index 314f6bc212..05b1aee22b 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -67,8 +67,9 @@ namespace MWClass virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 4a2a2ecc69..d34c4b97f5 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -155,6 +155,18 @@ namespace MWMechanics stat.setCurrent (stat.getModified()); creatureStats.setDynamic (i, stat); } + + // unequip any items that may not be equipped. we need this for when the race is changed to a beast race + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore(ptr); + for (int i=0; i result = MWWorld::Class::get (object).canBeEquipped (object, actor); + + // display error message if the player tried to equip something + if (!result.second.empty() && actor == MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) + MWBase::Environment::get().getWindowManager()->messageBox(result.second); + + switch(result.first) { case 0: return; @@ -48,8 +54,6 @@ namespace MWWorld assert(it != invStore.end()); - std::string npcRace = actor.get()->mBase->mRace; - bool equipped = false; // equip the item in the first free slot diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4321fc46b7..451f0c5c10 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -264,9 +264,9 @@ namespace MWWorld throw std::runtime_error ("class can't be enchanted"); } - int Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const + std::pair Class::canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const { - return 1; + return std::make_pair (1, ""); } void Class::adjustPosition(const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 32941c633d..b901950e31 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -245,8 +245,9 @@ namespace MWWorld virtual void applyEnchantment(const MWWorld::Ptr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const; - virtual int canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; + virtual std::pair canBeEquipped(const MWWorld::Ptr &ptr, const MWWorld::Ptr &npc) const; ///< Return 0 if player cannot equip item. 1 if can equip. 2 if it's twohanded weapon. 3 if twohanded weapon conflicts with that. + /// Second item in the pair specifies the error message virtual Ptr copyToCell(const Ptr &ptr, CellStore &cell) const; diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 5495d6a021..ac5586266d 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -186,7 +186,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& npc) } } - switch(MWWorld::Class::get (test).canBeEquipped (test, npc)) + switch(MWWorld::Class::get (test).canBeEquipped (test, npc).first) { case 0: continue; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e70aedd552..424f6f5089 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -24,6 +24,7 @@ #include "manualref.hpp" #include "cellfunctors.hpp" #include "containerstore.hpp" +#include "inventorystore.hpp" using namespace Ogre; @@ -210,9 +211,6 @@ namespace MWWorld mStore.setUp(); - mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); - mRendering->attachCameraTo(mPlayer->getPlayer()); - // global variables mGlobalVariables = new Globals (mStore); @@ -1369,6 +1367,18 @@ namespace MWWorld return mRendering->vanityRotateCamera(rot); } + void World::setupPlayer(bool newGame) + { + const ESM::NPC* player = mStore.get().find ("player"); + mPlayer = new MWWorld::Player (player, *this); + mRendering->attachCameraTo(mPlayer->getPlayer()); + if (newGame) + { + MWWorld::Class::get(mPlayer->getPlayer()).getContainerStore(mPlayer->getPlayer()).fill(player->mInventory, "", mStore); + MWWorld::Class::get(mPlayer->getPlayer()).getInventoryStore(mPlayer->getPlayer()).autoEquip (mPlayer->getPlayer()); + } + } + void World::renderPlayer() { mRendering->renderPlayer(mPlayer->getPlayer()); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee9..99e7cc79d9 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -363,6 +363,7 @@ namespace MWWorld virtual bool vanityRotateCamera(float * rot); + virtual void setupPlayer(bool newGame); virtual void renderPlayer(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); From 69084139aaf2c4711061dd62a84666d6f34c6d10 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Apr 2013 17:58:21 -0700 Subject: [PATCH 0431/1537] Use an array of objectlists, instead of one base objectlist and an array of 'animation sources' --- apps/openmw/mwrender/activatoranimation.cpp | 10 +- apps/openmw/mwrender/animation.cpp | 136 +++++++------------- apps/openmw/mwrender/animation.hpp | 14 +- apps/openmw/mwrender/creatureanimation.cpp | 21 ++- apps/openmw/mwrender/npcanimation.cpp | 27 ++-- 5 files changed, 75 insertions(+), 133 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 4630208b4b..27ddce339d 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -27,9 +27,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) std::string mesh = "meshes\\" + ref->mBase->mModel; createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,14 +38,12 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); } - setAnimationSource(mesh); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d6f762ab76..30bcd3c4c3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -55,68 +55,45 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - destroyObjectList(sceneMgr, mObjectList); - - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + for(size_t i = 0;i < mObjectLists.size();i++) + destroyObjectList(sceneMgr, mObjectLists[i]); + mObjectLists.clear(); } } -void Animation::setAnimationSources(const std::vector &names) +void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) { - if(!mSkelBase) - return; - Ogre::SceneManager *sceneMgr = mInsert->getCreator(); + assert(!mInsert); + mInsert = node->createChildSceneNode(); + assert(mInsert); - mCurrentControllers = &mObjectList.mControllers; - mCurrentAnim = NULL; - mCurrentKeys = NULL; - mAnimVelocity = 0.0f; - mAccumRoot = NULL; - mNonAccumRoot = NULL; - mTextKeys.clear(); - for(size_t i = 0;i < mAnimationSources.size();i++) - destroyObjectList(sceneMgr, mAnimationSources[i]); - mAnimationSources.clear(); + mObjectLists.resize(1); - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - std::vector::const_iterator nameiter; - for(nameiter = names.begin();nameiter != names.end();nameiter++) + mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); + if(mObjectLists[0].mSkelBase) { - mAnimationSources.push_back(NifOgre::Loader::createObjectBase(sceneMgr, *nameiter)); - if(!mAnimationSources.back().mSkelBase) + mSkelBase = mObjectLists[0].mSkelBase; + + Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); + while(asiter.hasMoreElements()) { - std::cerr<< "Failed to get skeleton source "<<*nameiter < *dstval = dynamic_cast*>(objects.mControllers[i].getDestination().getPointer()); - if(!dstval) continue; - - const Ogre::String &trgtname = dstval->getNode()->getName(); - if(!skelinst->hasBone(trgtname)) continue; - - Ogre::Bone *bone = skelinst->getBone(trgtname); - dstval->setNode(bone); + Ogre::AnimationState *state = asiter.getNext(); + state->setEnabled(false); + state->setLoop(false); } - for(size_t i = 0;i < objects.mControllers.size();i++) - { - if(objects.mControllers[i].getSource().isNull()) - objects.mControllers[i].setSource(ctrlval); - } + // Set the bones as manually controlled since we're applying the + // transformations manually (needed if we want to apply an animation + // from one skeleton onto another). + Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); + while(boneiter.hasMoreElements()) + boneiter.getNext()->setManuallyControlled(true); - Ogre::Entity *ent = objects.mSkelBase; - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(ent->getSkeleton()->getName()); - Ogre::Skeleton::BoneIterator boneiter = skel->getBoneIterator(); + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); + boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) { Ogre::Bone *bone = boneiter.getNext(); @@ -143,43 +120,14 @@ void Animation::setAnimationSources(const std::vector &names) break; } } -} - -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) -{ - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectList = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectList.mSkelBase) - { - mSkelBase = mObjectList.mSkelBase; - - Ogre::AnimationStateSet *aset = mSkelBase->getAllAnimationStates(); - Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); - while(asiter.hasMoreElements()) - { - Ogre::AnimationState *state = asiter.getNext(); - state->setEnabled(false); - state->setLoop(false); - } - - // Set the bones as manually controlled since we're applying the - // transformations manually (needed if we want to apply an animation - // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mSkelBase->getSkeleton(); - Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); - while(boneiter.hasMoreElements()) - boneiter.getNext()->setManuallyControlled(true); - } Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectList.mControllers.size();i++) + for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) { - if(mObjectList.mControllers[i].getSource().isNull()) - mObjectList.mControllers[i].setSource(ctrlval); + if(mObjectLists[0].mControllers[i].getSource().isNull()) + mObjectLists[0].mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectList.mControllers; + mCurrentControllers = &mObjectLists[0].mControllers; } @@ -197,9 +145,9 @@ Ogre::Node *Animation::getNode(const std::string &name) bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mAnimationSources.begin());iter != mAnimationSources.end();iter++) + for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase->hasAnimationState(anim)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) return true; } return false; @@ -449,7 +397,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con try { bool found = false; /* Look in reverse; last-inserted source has priority. */ - for(std::vector::reverse_iterator iter(mAnimationSources.rbegin());iter != mAnimationSources.rend();iter++) + for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase->hasAnimationState(groupname)) { @@ -513,9 +461,19 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(mSkelBase) { - // HACK: Dirty the animation state set so that Ogre will apply the - // transformations to entities this skeleton instance is shared with. - mSkelBase->getAllAnimationStates()->_notifyDirty(); + const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + for(size_t i = 0;i < mObjectLists.size();i++) + { + Ogre::Entity *ent = mObjectLists[i].mSkelBase; + if(!ent) continue; + + Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); + if(skelsrc != skeldst) + updateSkeletonInstance(skelsrc, skeldst); + // HACK: Dirty the animation state set so that Ogre will apply the + // transformations to entities this skeleton instance is shared with. + ent->getAllAnimationStates()->_notifyDirty(); + } } return movement; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 32344a2c02..3c7433db98 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -44,15 +44,13 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - NifOgre::ObjectList mObjectList; + std::vector mObjectLists; std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::vector mAnimationSources; - std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -83,16 +81,6 @@ protected: bool handleEvent(float time, const std::string &evt); - /* Specifies a list of skeleton names to use as animation sources. */ - void setAnimationSources(const std::vector &names); - - /* Specifies a single skeleton name to use as an animation source. */ - void setAnimationSource(const std::string &name) - { - std::vector names(1, name); - setAnimationSources(names); - } - void createObjectList(Ogre::SceneNode *node, const std::string &model); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index c714a2372a..7084974b8c 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,10 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), model); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector names; + if((ref->mBase->mFlags&ESM::Creature::Biped)) + names.push_back("meshes\\base_anim.nif"); + names.push_back(model); + + createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *ent = mObjectList.mEntities[i]; + Ogre::Entity *ent = mObjectLists[0].mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,19 +43,13 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->setVisibilityFlags(RV_Actors); part->setRenderQueueGroup(RQG_Alpha); } - - std::vector names; - if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); - setAnimationSources(names); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a2446b8671..a713ae79e1 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,10 +96,18 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - createObjectList(node, smodel); - for(size_t i = 0;i < mObjectList.mEntities.size();i++) + std::vector skelnames(1, smodel); + if(!mNpc->isMale() && !isBeast) + skelnames.push_back("meshes\\base_anim_female.nif"); + else if(mBodyPrefix.find("argonian") != std::string::npos) + skelnames.push_back("meshes\\argonian_swimkna.nif"); + if(mNpc->mModel.length() > 0) + skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); + + createObjectList(node, smodel/*skelnames*/); + for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) { - Ogre::Entity *base = mObjectList.mEntities[i]; + Ogre::Entity *base = mObjectLists[0].mEntities[i]; base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if (mVisibilityFlags != 0) @@ -111,9 +119,9 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectList.mParticles.size();i++) + for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectList.mParticles[i]; + Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); if(mVisibilityFlags != 0) @@ -121,15 +129,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor part->setRenderQueueGroup(RQG_Alpha); } - std::vector skelnames(1, smodel); - if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); - else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); - if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - setAnimationSources(skelnames); - forceUpdate(); } From 7fcaffefb09dc8f9a95660e9513ef88540d71b3c Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 15 Apr 2013 03:13:25 +0200 Subject: [PATCH 0432/1537] Fixed travel window to use the rotation part of ESM::Position --- apps/openmw/mwgui/travelwindow.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8eaa0d8c62..8389db0679 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -141,21 +141,22 @@ namespace MWGui int x,y; bool interior = _sender->getUserString("interior") == "y"; MWBase::Environment::get().getWorld()->positionToIndex(pos.pos[0],pos.pos[1],x,y); - MWWorld::CellStore* cell; - if(interior) cell = MWBase::Environment::get().getWorld()->getInterior(cellname); + if(interior) + MWBase::Environment::get().getWorld()->changeToInteriorCell(cellname, pos); else { - cell = MWBase::Environment::get().getWorld()->getExterior(x,y); - ESM::Position PlayerPos = player.getRefData().getPosition(); - float d = sqrt( pow(pos.pos[0] - PlayerPos.pos[0],2) + pow(pos.pos[1] - PlayerPos.pos[1],2) + pow(pos.pos[2] - PlayerPos.pos[2],2) ); - int time = int(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); - for(int i = 0;i < time;i++) + ESM::Position playerPos = player.getRefData().getPosition(); + float d = Ogre::Vector3(pos.pos[0], pos.pos[1], 0).distance( + Ogre::Vector3(playerPos.pos[0], playerPos.pos[1], 0)); + int hours = static_cast(d /MWBase::Environment::get().getWorld()->getStore().get().find("fTravelTimeMult")->getFloat()); + for(int i = 0;i < hours;i++) { MWBase::Environment::get().getMechanicsManager ()->restoreDynamicStats (); } - MWBase::Environment::get().getWorld()->advanceTime(time); + MWBase::Environment::get().getWorld()->advanceTime(hours); + + MWBase::Environment::get().getWorld()->changeToExteriorCell(pos); } - MWBase::Environment::get().getWorld()->moveObject(player,*cell,pos.pos[0],pos.pos[1],pos.pos[2]); MWWorld::Class::get(player).adjustPosition(player); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); From 972481f63f7ef724364b6cf9672aac50fc558788 Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 16:45:53 +0200 Subject: [PATCH 0433/1537] Working rotate, rotateworld --- apps/openmw/mwbase/windowmanager.hpp | 2 + apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwgui/windowmanagerimp.cpp | 5 ++ apps/openmw/mwgui/windowmanagerimp.hpp | 2 + apps/openmw/mwscript/docs/vmformat.txt | 4 +- .../mwscript/transformationextensions.cpp | 56 +++++++++++++++++-- apps/openmw/mwworld/worldimp.cpp | 6 ++ apps/openmw/mwworld/worldimp.hpp | 2 + 8 files changed, 73 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 976d7d84c1..b34117df29 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,6 +251,8 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 39e985890a..94a30d759b 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -230,6 +230,8 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; + virtual void localRotateObject (const MWWorld::Ptr& ptr, float rotation, Ogre::Vector3 axis) = 0; + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0; ///< place an object in a "safe" location (ie not in the void, etc). diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f994683a66..b3a080bf25 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,3 +1200,8 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } + +int WindowManager::getFPS() const +{ + return mFPS; +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3c9fc586a3..3a7296b5ba 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,6 +248,8 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); + virtual int getFPS() const; + private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 7810c2874b..b7ee2d31c6 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -320,5 +320,7 @@ op 0x20001fd: IsWerewolf op 0x20001fe: IsWerewolf, explicit reference op 0x20001ff: Rotate op 0x2000200: Rotate, explicit reference +op 0x2000201: RotateWorld +op 0x2000202: RotateWorld, explicit reference -opcodes 0x2000201-0x3ffffff unused +opcodes 0x2000203-0x3ffffff unused diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 922353974d..41bacf1106 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,6 +13,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -549,11 +550,11 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { - MWWorld::Ptr ptr = R()(runtime); + const MWWorld::Ptr& ptr = R()(runtime); std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/80); //It works this way, don't ask me why (probably framerate) + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -562,19 +563,22 @@ namespace MWScript { objRot[0]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_X));; + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { objRot[1]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Y)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { objRot[2]+=Ogre::Degree(rotation).valueRadians(); - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), Ogre::Vector3::UNIT_Z)); + if (ptr.getRefData().getBaseNode() != 0) + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } else @@ -582,6 +586,43 @@ namespace MWScript } }; + template + class OpRotateWorld : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + runtime.pop(); + + float *objRot = ptr.getRefData().getPosition().rot; + + float ax = Ogre::Radian(objRot[0]).valueDegrees(); + float ay = Ogre::Radian(objRot[1]).valueDegrees(); + float az = Ogre::Radian(objRot[2]).valueDegrees(); + + if (axis == "x") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax+rotation,ay,az); + } + else if (axis == "y") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay+rotation,az); + } + else if (axis == "z") + { + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,az+rotation); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -610,6 +651,8 @@ namespace MWScript const int opcodeModScaleExplicit = 0x20001e4; const int opcodeRotate = 0x20001ff; const int opcodeRotateExplicit = 0x2000200; + const int opcodeRotateWorld = 0x2000201; + const int opcodeRotateWorldExplicit = 0x2000202; void registerExtensions (Compiler::Extensions& extensions) { @@ -628,6 +671,7 @@ namespace MWScript extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); extensions.registerInstruction("rotate","cf",opcodeRotate,opcodeRotateExplicit); + extensions.registerInstruction("rotateworld","cf",opcodeRotateWorld,opcodeRotateWorldExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -659,6 +703,8 @@ namespace MWScript interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); interpreter.installSegment5(opcodeRotate,new OpRotate); interpreter.installSegment5(opcodeRotateExplicit,new OpRotate); + interpreter.installSegment5(opcodeRotateWorld,new OpRotateWorld); + interpreter.installSegment5(opcodeRotateWorldExplicit,new OpRotateWorld); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 11ccd8f2fc..c5ebbb306f 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,6 +826,12 @@ namespace MWWorld } } + void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) + { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } + void World::adjustPosition(const Ptr &ptr) { Ogre::Vector3 pos (ptr.getRefData().getPosition().pos[0], ptr.getRefData().getPosition().pos[1], ptr.getRefData().getPosition().pos[2]); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b12babee9..59a359b6b7 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -254,6 +254,8 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis); + virtual void safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos); ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr. From 763308868d501bc7bd7102d6a442855f8c155f1b Mon Sep 17 00:00:00 2001 From: Glorf Date: Mon, 15 Apr 2013 17:45:18 +0200 Subject: [PATCH 0434/1537] Fixed rotation speed --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ----- apps/openmw/mwgui/windowmanagerimp.hpp | 2 -- apps/openmw/mwscript/transformationextensions.cpp | 5 ++--- 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b34117df29..976d7d84c1 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,8 +251,6 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; - - virtual int getFPS() const = 0; }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index b3a080bf25..f994683a66 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1200,8 +1200,3 @@ void WindowManager::frameStarted (float dt) { mInventoryWindow->doRenderUpdate (); } - -int WindowManager::getFPS() const -{ - return mFPS; -} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3a7296b5ba..3c9fc586a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -248,8 +248,6 @@ namespace MWGui void onSoulgemDialogButtonPressed (int button); - virtual int getFPS() const; - private: OEngine::GUI::MyGUIManager *mGuiManager; OEngine::Render::OgreRenderer *mRendering; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 41bacf1106..8ac5a7802a 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -13,7 +13,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -554,7 +553,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; @@ -597,7 +596,7 @@ namespace MWScript std::string axis = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - Interpreter::Type_Float rotation = (runtime[0].mFloat/MWBase::Environment::get().getWindowManager()->getFPS()); + Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); float *objRot = ptr.getRefData().getPosition().rot; From 1b1f9f7921d91bc2c2c853cfc0b0f5c71fba0574 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 18:55:28 -0700 Subject: [PATCH 0435/1537] Allow multiple ObjectLists to be created for Animations. addObjectList may not currently be called outside of the related constructor. --- apps/openmw/mwrender/activatoranimation.cpp | 13 ++-- apps/openmw/mwrender/animation.cpp | 80 +++++++++++++-------- apps/openmw/mwrender/animation.hpp | 2 +- apps/openmw/mwrender/creatureanimation.cpp | 17 +++-- apps/openmw/mwrender/npcanimation.cpp | 39 +++------- components/nifogre/ogrenifloader.cpp | 7 +- components/nifogre/ogrenifloader.hpp | 2 +- 7 files changed, 82 insertions(+), 78 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 27ddce339d..1f9a2e23c9 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -24,12 +24,13 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) assert (ref->mBase != NULL); if(!ref->mBase->mModel.empty()) { - std::string mesh = "meshes\\" + ref->mBase->mModel; + const std::string name = "meshes\\"+ref->mBase->mModel; - createObjectList(mPtr.getRefData().getBaseNode(), mesh); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), name, false); + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Misc); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -38,9 +39,9 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Misc); part->setRenderQueueGroup(RQG_Alpha); } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 30bcd3c4c3..979046ea07 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -36,7 +36,7 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) - , mAccumulate(Ogre::Vector3::ZERO) + , mAccumulate(0.0f) , mLastPosition(0.0f) , mCurrentControllers(NULL) , mCurrentKeys(NULL) @@ -62,20 +62,24 @@ Animation::~Animation() } -void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model) +void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly) { - assert(!mInsert); - mInsert = node->createChildSceneNode(); - assert(mInsert); - - mObjectLists.resize(1); - - mObjectLists[0] = NifOgre::Loader::createObjects(mInsert, model); - if(mObjectLists[0].mSkelBase) + if(!mInsert) { - mSkelBase = mObjectLists[0].mSkelBase; + mInsert = node->createChildSceneNode(); + assert(mInsert); + } + Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - Ogre::AnimationStateSet *aset = mObjectLists[0].mSkelBase->getAllAnimationStates(); + mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + NifOgre::ObjectList &objlist = mObjectLists.back(); + if(objlist.mSkelBase) + { + if(!mSkelBase) + mSkelBase = objlist.mSkelBase; + + Ogre::AnimationStateSet *aset = objlist.mSkelBase->getAllAnimationStates(); Ogre::AnimationStateIterator asiter = aset->getAnimationStateIterator(); while(asiter.hasMoreElements()) { @@ -87,11 +91,28 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model // Set the bones as manually controlled since we're applying the // transformations manually (needed if we want to apply an animation // from one skeleton onto another). - Ogre::SkeletonInstance *skelinst = mObjectLists[0].mSkelBase->getSkeleton(); + Ogre::SkeletonInstance *skelinst = objlist.mSkelBase->getSkeleton(); Ogre::Skeleton::BoneIterator boneiter = skelinst->getBoneIterator(); while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + if(mSkelBase != objlist.mSkelBase) + { + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(!dstval) continue; + + const Ogre::String &trgtname = dstval->getNode()->getName(); + if(!baseinst->hasBone(trgtname)) continue; + + Ogre::Bone *bone = baseinst->getBone(trgtname); + dstval->setNode(bone); + } + } + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); boneiter = skel->getBoneIterator(); while(boneiter.hasMoreElements()) @@ -120,14 +141,14 @@ void Animation::createObjectList(Ogre::SceneNode *node, const std::string &model break; } } - - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); - for(size_t i = 0;i < mObjectLists[0].mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { - if(mObjectLists[0].mControllers[i].getSource().isNull()) - mObjectLists[0].mControllers[i].setSource(ctrlval); + if(objlist.mControllers[i].getSource().isNull()) + objlist.mControllers[i].setSource(ctrlval); } - mCurrentControllers = &mObjectLists[0].mControllers; + + if(!mCurrentControllers || (*mCurrentControllers).size() == 0) + mCurrentControllers = &objlist.mControllers; } @@ -399,9 +420,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - mCurrentAnim = iter->mSkelBase->getSkeleton()->getAnimation(groupname); + Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); + mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; mCurrentControllers = &iter->mControllers; mAnimVelocity = 0.0f; @@ -456,20 +478,22 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) if(!handleEvent(time, evt)) break; } - for(size_t i = 0;i < mCurrentControllers->size();i++) + + for(size_t i = 0;i < (*mCurrentControllers).size();i++) (*mCurrentControllers)[i].update(); if(mSkelBase) { - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); - for(size_t i = 0;i < mObjectLists.size();i++) + const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); + for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - Ogre::Entity *ent = mObjectLists[i].mSkelBase; + Ogre::Entity *ent = iter->mSkelBase; if(!ent) continue; - Ogre::SkeletonInstance *skeldst = ent->getSkeleton(); - if(skelsrc != skeldst) - updateSkeletonInstance(skelsrc, skeldst); + Ogre::SkeletonInstance *inst = ent->getSkeleton(); + if(baseinst != inst) + updateSkeletonInstance(baseinst, inst); + // HACK: Dirty the animation state set so that Ogre will apply the // transformations to entities this skeleton instance is shared with. ent->getAllAnimationStates()->_notifyDirty(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3c7433db98..79262f3c50 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -81,7 +81,7 @@ protected: bool handleEvent(float time, const std::string &evt); - void createObjectList(Ogre::SceneNode *node, const std::string &model); + void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); public: diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 7084974b8c..a48b8da9f8 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -26,15 +26,15 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) { std::string model = "meshes\\"+ref->mBase->mModel; - std::vector names; if((ref->mBase->mFlags&ESM::Creature::Biped)) - names.push_back("meshes\\base_anim.nif"); - names.push_back(model); + addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); - createObjectList(mPtr.getRefData().getBaseNode(), model/*names*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) + addObjectList(mPtr.getRefData().getBaseNode(), model, false); + + const NifOgre::ObjectList &objlist = mObjectLists.back(); + for(size_t i = 0;i < objlist.mEntities.size();i++) { - Ogre::Entity *ent = mObjectLists[0].mEntities[i]; + Ogre::Entity *ent = objlist.mEntities[i]; ent->setVisibilityFlags(RV_Actors); for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) @@ -43,11 +43,10 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) + for(size_t i = 0;i < objlist.mParticles.size();i++) { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; + Ogre::ParticleSystem *part = objlist.mParticles[i]; part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index a713ae79e1..3ef357440a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -96,38 +96,13 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; std::string smodel = (!isBeast ? "meshes\\base_anim.nif" : "meshes\\base_animkna.nif"); - std::vector skelnames(1, smodel); + addObjectList(node, smodel, true); if(!mNpc->isMale() && !isBeast) - skelnames.push_back("meshes\\base_anim_female.nif"); + addObjectList(node, "meshes\\base_anim_female.nif", true); else if(mBodyPrefix.find("argonian") != std::string::npos) - skelnames.push_back("meshes\\argonian_swimkna.nif"); + addObjectList(node, "meshes\\argonian_swimkna.nif", true); if(mNpc->mModel.length() > 0) - skelnames.push_back("meshes\\"+Misc::StringUtils::lowerCase(mNpc->mModel)); - - createObjectList(node, smodel/*skelnames*/); - for(size_t i = 0;i < mObjectLists[0].mEntities.size();i++) - { - Ogre::Entity *base = mObjectLists[0].mEntities[i]; - - base->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if (mVisibilityFlags != 0) - base->setVisibilityFlags(mVisibilityFlags); - - for(unsigned int j=0; j < base->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = base->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < mObjectLists[0].mParticles.size();i++) - { - Ogre::ParticleSystem *part = mObjectLists[0].mParticles[i]; - - part->getUserObjectBindings().setUserAny(Ogre::Any(-1)); - if(mVisibilityFlags != 0) - part->setVisibilityFlags(mVisibilityFlags); - part->setRenderQueueGroup(RQG_Alpha); - } + addObjectList(node, "meshes\\"+mNpc->mModel, true); forceUpdate(); } @@ -406,14 +381,16 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed) mTimeToChange -= timepassed; Ogre::Vector3 ret = Animation::runAnimation(timepassed); - const Ogre::SkeletonInstance *skelsrc = mSkelBase->getSkeleton(); + + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < sPartListSize;i++) { Ogre::Entity *ent = mObjectParts[i].mSkelBase; if(!ent) continue; - updateSkeletonInstance(skelsrc, ent->getSkeleton()); + updateSkeletonInstance(baseinst, ent->getSkeleton()); ent->getAllAnimationStates()->_notifyDirty(); } + return ret; } diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 69f14b663d..04cdb142f6 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -800,12 +800,15 @@ ObjectList Loader::createObjects(Ogre::Entity *parent, const std::string &bonena } -ObjectList Loader::createObjectBase(Ogre::SceneManager *sceneMgr, std::string name, const std::string &group) +ObjectList Loader::createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group) { ObjectList objectlist; Misc::StringUtils::toLower(name); - NIFObjectLoader::load(sceneMgr, objectlist, name, group, 0xC0000000); + NIFObjectLoader::load(parentNode->getCreator(), objectlist, name, group, 0xC0000000); + + if(objectlist.mSkelBase) + parentNode->attachObject(objectlist.mSkelBase); return objectlist; } diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index fa5182aeaa..e3bb550640 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -69,7 +69,7 @@ public: std::string name, const std::string &group="General"); - static ObjectList createObjectBase(Ogre::SceneManager *sceneMgr, + static ObjectList createObjectBase(Ogre::SceneNode *parentNode, std::string name, const std::string &group="General"); }; From 4ce98e9bd65ff2035e2f36e89a90cb6f892472fe Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 15 Apr 2013 20:37:10 -0700 Subject: [PATCH 0436/1537] Store iterators for start and stop keys --- apps/openmw/mwrender/animation.cpp | 51 ++++++++++++------------------ apps/openmw/mwrender/animation.hpp | 7 ++-- 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 979046ea07..11876a2473 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -38,11 +38,10 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) + , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) - , mCurrentAnim(NULL) , mCurrentTime(0.0f) - , mStopTime(0.0f) , mPlaying(false) , mLooping(false) , mAnimVelocity(0.0f) @@ -313,35 +312,26 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { - mNextKey = mCurrentKeys->begin(); + mStartKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != start) - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + mStartKey++; + if(mStartKey != mCurrentKeys->end()) + mCurrentTime = mStartKey->first; else { - mNextKey = mCurrentKeys->begin(); - while(mNextKey != mCurrentKeys->end() && mNextKey->second != "start") - mNextKey++; - if(mNextKey != mCurrentKeys->end()) - mCurrentTime = mNextKey->first; - else - { - mNextKey = mCurrentKeys->begin(); - mCurrentTime = 0.0f; - } + mStartKey = mCurrentKeys->begin(); + mCurrentTime = mStartKey->first; } + mNextKey = mStartKey; if(stop.length() > 0) { - NifOgre::TextKeyMap::const_iterator stopKey = mNextKey; - while(stopKey != mCurrentKeys->end() && stopKey->second != stop) - stopKey++; - if(stopKey != mCurrentKeys->end()) - mStopTime = stopKey->first; - else - mStopTime = mCurrentAnim->getLength(); + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; } if(mNonAccumRoot) @@ -390,7 +380,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; } @@ -400,7 +390,7 @@ bool Animation::handleEvent(float time, const std::string &evt) { if(mLooping) { - reset("loop start", ""); + reset("loop start"); if(mCurrentTime >= time) return false; return true; @@ -455,13 +445,11 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) while(mCurrentAnim && mPlaying) { float targetTime = mCurrentTime + timepassed; - if(mNextKey == mCurrentKeys->end() || mNextKey->first > targetTime) + if(mNextKey->first > targetTime) { - mCurrentTime = std::min(mStopTime, targetTime); + mCurrentTime = targetTime; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); - timepassed = targetTime - mCurrentTime; break; } @@ -472,7 +460,8 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) mCurrentTime = time; if(mNonAccumRoot) movement += updatePosition(); - mPlaying = (mLooping || mStopTime > mCurrentTime); + + mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; if(!handleEvent(time, evt)) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 79262f3c50..f8ddceeaa3 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,13 +50,14 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; + Ogre::Animation *mCurrentAnim; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; - Ogre::Animation *mCurrentAnim; float mCurrentTime; - float mStopTime; bool mPlaying; bool mLooping; @@ -77,7 +78,7 @@ protected: * moving anything, and set the end time to the specified stop marker. If * the marker is not found, it resets to the beginning or end respectively. */ - void reset(const std::string &start, const std::string &stop); + void reset(const std::string &start, const std::string &stop=std::string()); bool handleEvent(float time, const std::string &evt); From 36170c5374402f06b49bcf63d7c856572072ebda Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 01:20:32 -0700 Subject: [PATCH 0437/1537] Use flag enums instead of hard-coded hex values --- components/nif/node.hpp | 18 +++++++------ components/nifbullet/bulletnifloader.cpp | 6 ++--- components/nifogre/ogrenifloader.cpp | 32 +++++++++++++----------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/components/nif/node.hpp b/components/nif/node.hpp index 9c345baab2..917bc8add3 100644 --- a/components/nif/node.hpp +++ b/components/nif/node.hpp @@ -128,13 +128,17 @@ struct NiNode : Node NodeList children; NodeList effects; - /* Known NiNode flags: - 0x01 hidden - 0x02 use mesh for collision - 0x04 use bounding box for collision (?) - 0x08 unknown, but common - 0x20, 0x40, 0x80 unknown - */ + enum Flags { + Flag_Hidden = 0x0001, + Flag_MeshCollision = 0x0002, + Flag_BBoxCollision = 0x0004 + }; + enum BSAnimFlags { + AnimFlag_AutoPlay = 0x0020 + }; + enum BSParticleFlags { + ParticleFlag_AutoPlay = 0x0020 + }; void read(NIFStream *nif) { diff --git a/components/nifbullet/bulletnifloader.cpp b/components/nifbullet/bulletnifloader.cpp index 6bd43f6e35..a3eff95c3e 100644 --- a/components/nifbullet/bulletnifloader.cpp +++ b/components/nifbullet/bulletnifloader.cpp @@ -255,9 +255,9 @@ void ManualBulletShapeLoader::handleNiTriShape(btTriangleMesh* mesh, const Nif:: assert(shape != NULL); // Interpret flags - bool hidden = (flags & 0x01) != 0; // Not displayed - bool collide = (flags & 0x02) != 0; // Use mesh for collision - bool bbcollide = (flags & 0x04) != 0; // Use bounding box for collision + bool hidden = (flags&Nif::NiNode::Flag_Hidden) != 0; + bool collide = (flags&Nif::NiNode::Flag_MeshCollision) != 0; + bool bbcollide = (flags&Nif::NiNode::Flag_BBoxCollision) != 0; // If the object was marked "NCO" earlier, it shouldn't collide with // anything. So don't do anything. diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 04cdb142f6..2e77adb082 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -394,7 +394,7 @@ class NIFObjectLoader NIFMeshLoader::createMesh(name, fullname, group, shape->recIndex); Ogre::Entity *entity = sceneMgr->createEntity(fullname); - entity->setVisible(!(flags&0x01)); + entity->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mEntities.push_back(entity); if(objectlist.mSkelBase) @@ -417,10 +417,11 @@ class NIFObjectLoader const Nif::NiUVController *uv = static_cast(ctrl.getPtr()); const Ogre::MaterialPtr &material = entity->getSubEntity(0)->getMaterial(); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW UVController::Value(material, uv->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW UVController::Function(uv, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -551,10 +552,11 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - Ogre::ControllerValueRealPtr srcval((partflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((partflags&Nif::NiNode::ParticleFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW ParticleSystemController::Value(partsys, partctrl)); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW ParticleSystemController::Function(partctrl, (partflags&Nif::NiNode::ParticleFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -568,7 +570,7 @@ class NIFObjectLoader objectlist.mSkelBase->attachObjectToBone(trgtbone->getName(), partsys); } - partsys->setVisible(!(flags&0x01)); + partsys->setVisible(!(flags&Nif::NiNode::Flag_Hidden)); objectlist.mParticles.push_back(partsys); } @@ -627,10 +629,11 @@ class NIFObjectLoader int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } @@ -641,10 +644,11 @@ class NIFObjectLoader { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&0x20) ? Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&0x20))); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } From 518cb0e3b7a181462bb7044ae966a9bcf18659c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 16 Apr 2013 12:12:04 +0200 Subject: [PATCH 0438/1537] added another abstraction layer to ID access in IdCollection --- apps/opencs/model/world/idcollection.hpp | 123 +++++++++++++---------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 4afe9cbaab..7052b300e4 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -79,8 +79,29 @@ namespace CSMWorld virtual void load (ESM::ESMReader& reader, bool base) = 0; }; - ///< \brief Collection of ID-based records + ///< \brief Access to ID field in records template + struct IdAccessor + { + std::string& getId (ESXRecordT& record); + + const std::string getId (const ESXRecordT& record) const; + }; + + template + std::string& IdAccessor::getId (ESXRecordT& record) + { + return record.mId; + } + + template + const std::string IdAccessor::getId (const ESXRecordT& record) const + { + return record.mId; + } + + ///< \brief Collection of ID-based records + template > class IdCollection : public IdCollectionBase { std::vector > mRecords; @@ -150,21 +171,21 @@ namespace CSMWorld void addColumn (Column *column); }; - template - IdCollection::IdCollection() + template + IdCollection::IdCollection() {} - template - IdCollection::~IdCollection() + template + IdCollection::~IdCollection() { for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) delete *iter; } - template - void IdCollection::add (const ESXRecordT& record) + template + void IdCollection::add (const ESXRecordT& record) { - std::string id = Misc::StringUtils::lowerCase(record.mId); + std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record)); std::map::iterator iter = mIndex.find (id); @@ -183,20 +204,20 @@ namespace CSMWorld } } - template - int IdCollection::getSize() const + template + int IdCollection::getSize() const { return mRecords.size(); } - template - std::string IdCollection::getId (int index) const + template + std::string IdCollection::getId (int index) const { - return mRecords.at (index).get().mId; + return IdAccessorT().getId (mRecords.at (index).get()); } - template - int IdCollection::getIndex (const std::string& id) const + template + int IdCollection::getIndex (const std::string& id) const { int index = searchId (id); @@ -206,38 +227,38 @@ namespace CSMWorld return index; } - template - int IdCollection::getColumns() const + template + int IdCollection::getColumns() const { return mColumns.size(); } - template - QVariant IdCollection::getData (int index, int column) const + template + QVariant IdCollection::getData (int index, int column) const { return mColumns.at (column)->get (mRecords.at (index)); } - template - void IdCollection::setData (int index, int column, const QVariant& data) + template + void IdCollection::setData (int index, int column, const QVariant& data) { return mColumns.at (column)->set (mRecords.at (index), data); } - template - const ColumnBase& IdCollection::getColumn (int column) const + template + const ColumnBase& IdCollection::getColumn (int column) const { return *mColumns.at (column); } - template - void IdCollection::addColumn (Column *column) + template + void IdCollection::addColumn (Column *column) { mColumns.push_back (column); } - template - void IdCollection::merge() + template + void IdCollection::merge() { for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) iter->merge(); @@ -245,16 +266,16 @@ namespace CSMWorld purge(); } - template - void IdCollection::purge() + template + void IdCollection::purge() { mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(), std::mem_fun_ref (&Record::isErased) // I want lambda :( ), mRecords.end()); } - template - void IdCollection::removeRows (int index, int count) + template + void IdCollection::removeRows (int index, int count) { mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); @@ -278,17 +299,17 @@ namespace CSMWorld } } - template - void IdCollection::appendBlankRecord (const std::string& id) + template + void IdCollection::appendBlankRecord (const std::string& id) { ESXRecordT record; - record.mId = id; + IdAccessorT().getId (record) = id; record.blank(); add (record); } - template - int IdCollection::searchId (const std::string& id) const + template + int IdCollection::searchId (const std::string& id) const { std::string id2 = Misc::StringUtils::lowerCase(id); @@ -300,28 +321,28 @@ namespace CSMWorld return iter->second; } - template - void IdCollection::replace (int index, const RecordBase& record) + template + void IdCollection::replace (int index, const RecordBase& record) { mRecords.at (index) = dynamic_cast&> (record); } - template - void IdCollection::appendRecord (const RecordBase& record) + template + void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (getId (record)), mRecords.size()-1)); } - template - std::string IdCollection::getId (const RecordBase& record) const + template + std::string IdCollection::getId (const RecordBase& record) const { const Record& record2 = dynamic_cast&> (record); - return (record2.isModified() ? record2.mModified : record2.mBase).mId; + return IdAccessorT().getId (record2.isModified() ? record2.mModified : record2.mBase); } - template - void IdCollection::load (ESM::ESMReader& reader, bool base) + template + void IdCollection::load (ESM::ESMReader& reader, bool base) { std::string id = reader.getHNOString ("NAME"); @@ -351,10 +372,10 @@ namespace CSMWorld else { ESXRecordT record; - record.mId = id; + IdAccessorT().getId (record) = id; record.load (reader); - int index = searchId (record.mId); + int index = searchId (IdAccessorT().getId (record)); if (index==-1) { @@ -378,15 +399,15 @@ namespace CSMWorld } } - template - const Record& IdCollection::getRecord (const std::string& id) const + template + const Record& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } - template - const Record& IdCollection::getRecord (int index) const + template + const Record& IdCollection::getRecord (int index) const { return mRecords.at (index); } From 1e92ffc3147229b9d1b08e972b4372f7b8ca9f49 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:17:19 +0200 Subject: [PATCH 0439/1537] Added rotation layer --- .../mwscript/transformationextensions.cpp | 27 +++++++++---------- apps/openmw/mwworld/refdata.cpp | 12 ++++++++- apps/openmw/mwworld/refdata.hpp | 10 +++++++ apps/openmw/mwworld/scene.cpp | 7 +++++ apps/openmw/mwworld/worldimp.cpp | 6 +++-- 5 files changed, 44 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 8ac5a7802a..e2d701268b 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -102,6 +102,11 @@ namespace MWScript } else throw std::runtime_error ("invalid ration axis: " + axis); + + //Local rotations clear + ptr.getRefData().getLocalRotation().rot[0]=0; + ptr.getRefData().getLocalRotation().rot[1]=0; + ptr.getRefData().getLocalRotation().rot[2]=0; } }; @@ -148,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -556,27 +561,19 @@ namespace MWScript Interpreter::Type_Float rotation = (runtime[0].mFloat*MWBase::Environment::get().getFrameDuration()); runtime.pop(); - float *objRot = ptr.getRefData().getPosition().rot; - if (axis == "x") { - objRot[0]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) - MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - objRot[1]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - objRot[2]+=Ogre::Degree(rotation).valueRadians(); - - if (ptr.getRefData().getBaseNode() != 0) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 4be2878104..db565c4513 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -19,6 +19,7 @@ namespace MWWorld mEnabled = refData.mEnabled; mCount = refData.mCount; mPosition = refData.mPosition; + mLocalRotation = refData.mLocalRotation; mCustomData = refData.mCustomData ? refData.mCustomData->clone() : 0; } @@ -34,7 +35,11 @@ namespace MWWorld RefData::RefData (const ESM::CellRef& cellRef) : mBaseNode(0), mHasLocals (false), mEnabled (true), mCount (1), mPosition (cellRef.mPos), mCustomData (0) - {} + { + mLocalRotation.rot[0]=0; + mLocalRotation.rot[1]=0; + mLocalRotation.rot[2]=0; + } RefData::RefData (const RefData& refData) : mBaseNode(0), mCustomData (0) @@ -141,6 +146,11 @@ namespace MWWorld return mPosition; } + LocalRotation& RefData::getLocalRotation() + { + return mLocalRotation; + } + void RefData::setCustomData (CustomData *data) { delete mCustomData; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 3a6e0fc9fd..c3aa647ec2 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,6 +5,8 @@ #include "../mwscript/locals.hpp" +#include + namespace Ogre { class SceneNode; @@ -18,6 +20,10 @@ namespace ESM namespace MWWorld { + struct LocalRotation{ + float rot[3]; + }; + class CustomData; class RefData @@ -34,6 +40,8 @@ namespace MWWorld ESM::Position mPosition; + LocalRotation mLocalRotation; + CustomData *mCustomData; void copy (const RefData& refData); @@ -78,6 +86,8 @@ namespace MWWorld ESM::Position& getPosition(); + LocalRotation& getLocalRotation(); + void setCustomData (CustomData *data); ///< Set custom data (potentially replacing old custom data). The ownership of \æ data is /// transferred to this. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f761311..b11b59ac62 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -50,6 +50,13 @@ namespace rendering.addObject(ptr); class_.insertObject(ptr, physics); MWBase::Environment::get().getWorld()->rotateObject(ptr, 0, 0, 0, true); + + //To keep local-rotations + const float *local = ptr.getRefData().getLocalRotation().rot; + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[0], Ogre::Vector3::UNIT_X); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[1], Ogre::Vector3::UNIT_Y); + MWBase::Environment::get().getWorld()->localRotateObject(ptr, local[2], Ogre::Vector3::UNIT_Z); + MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().mScale); class_.adjustPosition(ptr); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 52d0d953a0..69bcad619d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -826,8 +826,10 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { - ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); - mPhysics->rotateObject(ptr); + if (ptr.getRefData().getBaseNode() != 0) { + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); + mPhysics->rotateObject(ptr); + } } void World::adjustPosition(const Ptr &ptr) From 1fd59d0ce0c63e893f6203a723579d25dc3ec7c9 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:21:54 +0200 Subject: [PATCH 0440/1537] Removed useless include --- apps/openmw/mwworld/refdata.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index c3aa647ec2..77ceb3721a 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -5,8 +5,6 @@ #include "../mwscript/locals.hpp" -#include - namespace Ogre { class SceneNode; From e3a9f73eb6008159b3ba1fa1fa15451050360407 Mon Sep 17 00:00:00 2001 From: Glorf Date: Tue, 16 Apr 2013 21:40:34 +0200 Subject: [PATCH 0441/1537] Improved getangle script behaviour --- apps/openmw/mwscript/transformationextensions.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index e2d701268b..beb6c3d8c1 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]+ptr.getRefData().getLocalRotation().rot[0]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]+ptr.getRefData().getLocalRotation().rot[1]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]+ptr.getRefData().getLocalRotation().rot[2]).valueDegrees()); + runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); From 60fadaeaf0368df6c6bafafbabe24a233a74d124 Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Tue, 16 Apr 2013 20:16:22 -0400 Subject: [PATCH 0442/1537] Cleaned up includes in implementation files --- apps/openmw/mwgui/alchemywindow.cpp | 2 -- apps/openmw/mwgui/alchemywindow.hpp | 1 - apps/openmw/mwgui/birth.cpp | 2 -- apps/openmw/mwgui/charactercreation.cpp | 2 -- apps/openmw/mwgui/class.cpp | 5 ----- apps/openmw/mwgui/companionwindow.cpp | 1 - apps/openmw/mwgui/confirmationdialog.cpp | 5 ----- apps/openmw/mwgui/console.cpp | 6 ------ apps/openmw/mwgui/container.cpp | 12 ------------ apps/openmw/mwgui/countdialog.cpp | 3 --- apps/openmw/mwgui/cursor.cpp | 2 -- apps/openmw/mwgui/dialogue.cpp | 9 +-------- apps/openmw/mwgui/formatting.cpp | 1 - apps/openmw/mwgui/hud.cpp | 10 ---------- apps/openmw/mwgui/inventorywindow.cpp | 13 ------------- apps/openmw/mwgui/journalwindow.cpp | 3 --- apps/openmw/mwgui/levelupdialog.cpp | 2 -- apps/openmw/mwgui/loadingscreen.cpp | 9 --------- apps/openmw/mwgui/mainmenu.cpp | 1 - apps/openmw/mwgui/mapwindow.cpp | 4 ---- apps/openmw/mwgui/merchantrepair.cpp | 3 --- apps/openmw/mwgui/quickkeysmenu.cpp | 4 ---- apps/openmw/mwgui/race.cpp | 6 ------ apps/openmw/mwgui/review.cpp | 6 ------ apps/openmw/mwgui/settingswindow.cpp | 6 ------ apps/openmw/mwgui/soulgemdialog.cpp | 1 - apps/openmw/mwgui/spellbuyingwindow.cpp | 4 ---- apps/openmw/mwgui/spellcreationdialog.cpp | 8 -------- apps/openmw/mwgui/spellicons.cpp | 5 ----- apps/openmw/mwgui/spellwindow.cpp | 8 -------- apps/openmw/mwgui/statswindow.cpp | 6 ------ apps/openmw/mwgui/tooltips.cpp | 7 ------- apps/openmw/mwgui/tradewindow.cpp | 1 - apps/openmw/mwgui/travelwindow.cpp | 7 ------- apps/openmw/mwgui/waitdialog.cpp | 4 ---- apps/openmw/mwgui/widgets.cpp | 2 -- apps/openmw/mwgui/windowbase.cpp | 2 -- apps/openmw/mwgui/windowmanagerimp.cpp | 23 +---------------------- apps/openmw/mwgui/windowpinnablebase.cpp | 2 -- 39 files changed, 2 insertions(+), 196 deletions(-) diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index a6121c234c..24a4e205bf 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -8,8 +8,6 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/containerstore.hpp" namespace { diff --git a/apps/openmw/mwgui/alchemywindow.hpp b/apps/openmw/mwgui/alchemywindow.hpp index 655a832c17..9189e4a631 100644 --- a/apps/openmw/mwgui/alchemywindow.hpp +++ b/apps/openmw/mwgui/alchemywindow.hpp @@ -10,7 +10,6 @@ namespace MWGui { - class AlchemyWindow : public WindowBase, public ContainerBase { public: diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 133bbd32fb..9c3ebdc7dc 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -3,8 +3,6 @@ #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 0dd6502c6c..28f6d13ee2 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -5,8 +5,6 @@ #include "class.hpp" #include "birth.hpp" #include "review.hpp" -#include "dialogue.hpp" -#include "mode.hpp" #include "inventorywindow.hpp" #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 6edad9e83b..e4d32c933b 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -1,11 +1,6 @@ #include "class.hpp" -#include - #include -#include - -#include "../mwworld/esmstore.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwgui/companionwindow.cpp b/apps/openmw/mwgui/companionwindow.cpp index 0a20c471ab..22afc42f6d 100644 --- a/apps/openmw/mwgui/companionwindow.cpp +++ b/apps/openmw/mwgui/companionwindow.cpp @@ -2,7 +2,6 @@ #include -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/dialoguemanager.hpp" diff --git a/apps/openmw/mwgui/confirmationdialog.cpp b/apps/openmw/mwgui/confirmationdialog.cpp index 904468f886..f431f2f64c 100644 --- a/apps/openmw/mwgui/confirmationdialog.cpp +++ b/apps/openmw/mwgui/confirmationdialog.cpp @@ -1,10 +1,5 @@ #include "confirmationdialog.hpp" -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { ConfirmationDialog::ConfirmationDialog() : diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index 1aebe57da2..bd1b0fe7ab 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -1,13 +1,7 @@ - #include "console.hpp" -#include -#include - #include -#include "../mwworld/esmstore.hpp" - #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 8ee4754a32..d15a5acd3e 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -1,11 +1,5 @@ #include "container.hpp" -#include -#include -#include -#include -#include - #include #include "../mwbase/environment.hpp" @@ -13,15 +7,9 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/containerstore.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwclass/container.hpp" - -#include "widgets.hpp" #include "countdialog.hpp" #include "tradewindow.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index d017cc1986..fe5122455c 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -2,9 +2,6 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - namespace MWGui { CountDialog::CountDialog() : diff --git a/apps/openmw/mwgui/cursor.cpp b/apps/openmw/mwgui/cursor.cpp index b0d164bedf..c069eca15a 100644 --- a/apps/openmw/mwgui/cursor.cpp +++ b/apps/openmw/mwgui/cursor.cpp @@ -2,13 +2,11 @@ #include #include -#include #include #include #include - namespace MWGui { diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index f3c11752e8..392f641264 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,18 +1,11 @@ #include "dialogue.hpp" -#include -#include - -#include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" -#include "../mwbase/dialoguemanager.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwmechanics/npcstats.hpp" diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 7f28e9e17d..b21b903bde 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -3,7 +3,6 @@ #include #include "../mwscript/interpretercontext.hpp" -#include "../mwworld/ptr.hpp" #include #include diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 84526a28dd..988bcfc241 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,24 +1,14 @@ #include "hud.hpp" -#include - -#include -#include - #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwgui/widgets.hpp" - #include "inventorywindow.hpp" -#include "container.hpp" #include "console.hpp" #include "spellicons.hpp" diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 40c228fd5a..e5e20b778b 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -1,28 +1,15 @@ #include "inventorywindow.hpp" -#include -#include -#include -#include - #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/containerstore.hpp" -#include "../mwworld/class.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwworld/actiontake.hpp" #include "../mwworld/inventorystore.hpp" -#include "widgets.hpp" #include "bookwindow.hpp" #include "scrollwindow.hpp" #include "spellwindow.hpp" diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 35a687cc4a..23588a4afa 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -4,9 +4,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/journal.hpp" #include "../mwbase/soundmanager.hpp" -#include "../mwbase/windowmanager.hpp" - -#include "../mwdialogue/journalentry.hpp" namespace { diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp index fc1317e908..5857db4d2e 100644 --- a/apps/openmw/mwgui/levelupdialog.cpp +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -8,12 +8,10 @@ #include "../mwworld/player.hpp" #include "../mwworld/class.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/fallback.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/npcstats.hpp" -#include "../mwmechanics/stat.hpp" namespace MWGui { diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 858c3f36ec..3b341574d9 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -1,25 +1,16 @@ #include "loadingscreen.hpp" #include -#include #include #include -#include - - -#include #include #include "../mwbase/environment.hpp" -#include "../mwbase/inputmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include - - namespace MWGui { diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index 5402d35428..ebd31d92cf 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -3,7 +3,6 @@ #include #include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 17834be937..1ac1c24480 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -2,12 +2,8 @@ #include -#include -#include #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwgui/merchantrepair.cpp b/apps/openmw/mwgui/merchantrepair.cpp index 53148cb3f0..a98051c287 100644 --- a/apps/openmw/mwgui/merchantrepair.cpp +++ b/apps/openmw/mwgui/merchantrepair.cpp @@ -9,10 +9,7 @@ #include "../mwbase/soundmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/containerstore.hpp" -#include "../mwworld/class.hpp" -#include "list.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 2deb37d301..a44f1791c4 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -2,13 +2,9 @@ #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" #include "../mwgui/inventorywindow.hpp" #include "../mwgui/bookwindow.hpp" diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 9a0d8a029f..c031ad6b68 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -1,19 +1,13 @@ #include "race.hpp" -#include -#include - #include #include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "widgets.hpp" #include "tooltips.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 562bf97748..31f5d737b9 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -1,17 +1,11 @@ #include "review.hpp" -#include - -#include #include -#include "../mwworld/esmstore.hpp" - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "widgets.hpp" #include "tooltips.hpp" #undef min diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 93b82e3745..39ee4e01d0 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -1,24 +1,18 @@ #include "settingswindow.hpp" #include -#include #include -#include #include #include #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwrender/renderingmanager.hpp" - #include "confirmationdialog.hpp" namespace diff --git a/apps/openmw/mwgui/soulgemdialog.cpp b/apps/openmw/mwgui/soulgemdialog.cpp index 4530a13d0b..b95eec0b67 100644 --- a/apps/openmw/mwgui/soulgemdialog.cpp +++ b/apps/openmw/mwgui/soulgemdialog.cpp @@ -1,6 +1,5 @@ #include "soulgemdialog.hpp" -#include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "messagebox.hpp" diff --git a/apps/openmw/mwgui/spellbuyingwindow.cpp b/apps/openmw/mwgui/spellbuyingwindow.cpp index 7d634df8d6..cb20075650 100644 --- a/apps/openmw/mwgui/spellbuyingwindow.cpp +++ b/apps/openmw/mwgui/spellbuyingwindow.cpp @@ -1,7 +1,5 @@ #include "spellbuyingwindow.hpp" -#include - #include #include "../mwbase/environment.hpp" @@ -11,9 +9,7 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" -#include "../mwmechanics/spells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" diff --git a/apps/openmw/mwgui/spellcreationdialog.cpp b/apps/openmw/mwgui/spellcreationdialog.cpp index e1df9f9cd1..45cf1b0aaa 100644 --- a/apps/openmw/mwgui/spellcreationdialog.cpp +++ b/apps/openmw/mwgui/spellcreationdialog.cpp @@ -4,22 +4,14 @@ #include "../mwbase/windowmanager.hpp" -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/class.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" - #include "tooltips.hpp" -#include "widgets.hpp" #include "class.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/spellicons.cpp b/apps/openmw/mwgui/spellicons.cpp index 206db51ed0..e762cc6105 100644 --- a/apps/openmw/mwgui/spellicons.cpp +++ b/apps/openmw/mwgui/spellicons.cpp @@ -1,9 +1,5 @@ #include "spellicons.hpp" -#include -#include -#include - #include #include "../mwbase/world.hpp" @@ -14,7 +10,6 @@ #include "../mwworld/class.hpp" #include "../mwworld/inventorystore.hpp" -#include "../mwmechanics/activespells.hpp" #include "../mwmechanics/creaturestats.hpp" #include "tooltips.hpp" diff --git a/apps/openmw/mwgui/spellwindow.cpp b/apps/openmw/mwgui/spellwindow.cpp index d07f9ca542..bd1fef12b3 100644 --- a/apps/openmw/mwgui/spellwindow.cpp +++ b/apps/openmw/mwgui/spellwindow.cpp @@ -1,22 +1,14 @@ #include "spellwindow.hpp" -#include #include #include -#include "../mwworld/esmstore.hpp" - -#include "../mwbase/world.hpp" -#include "../mwbase/environment.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/actionequip.hpp" -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/spellsuccess.hpp" #include "spellicons.hpp" diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index a00ec167da..3439ff31ce 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -1,14 +1,9 @@ #include "statswindow.hpp" -#include -#include -#include - #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwworld/player.hpp" @@ -18,7 +13,6 @@ #include "tooltips.hpp" - using namespace MWGui; const int StatsWindow::sLineHeight = 18; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 2250ffd0b5..b72d27aeae 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -2,18 +2,11 @@ #include -#include - -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/class.hpp" - #include "mapwindow.hpp" -#include "widgets.hpp" #include "inventorywindow.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index f3f226974e..23bb6554f6 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -9,7 +9,6 @@ #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/dialoguemanager.hpp" -#include "../mwworld/inventorystore.hpp" #include "../mwworld/manualref.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index 8eaa0d8c62..780ffa0569 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -1,22 +1,15 @@ #include "travelwindow.hpp" -#include - #include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -#include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/manualref.hpp" - -#include "../mwmechanics/spells.hpp" -#include "../mwmechanics/creaturestats.hpp" #include "inventorywindow.hpp" #include "tradewindow.hpp" diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index a84b9203a9..ad2b4710cc 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -1,7 +1,5 @@ #include "waitdialog.hpp" -#include - #include #include @@ -11,9 +9,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/mechanicsmanager.hpp" -#include "../mwworld/timestamp.hpp" #include "../mwworld/player.hpp" -#include "../mwworld/ptr.hpp" #include "../mwworld/class.hpp" #include "../mwmechanics/creaturestats.hpp" diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index dd3206ed65..e6c8b1d77d 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -9,8 +9,6 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwworld/esmstore.hpp" - #undef min #undef max diff --git a/apps/openmw/mwgui/windowbase.cpp b/apps/openmw/mwgui/windowbase.cpp index c41bcb7ce6..cc74579abf 100644 --- a/apps/openmw/mwgui/windowbase.cpp +++ b/apps/openmw/mwgui/windowbase.cpp @@ -1,7 +1,5 @@ #include "windowbase.hpp" -#include - #include "../mwbase/windowmanager.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index f2ded8813e..154234bee5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1,39 +1,20 @@ #include "windowmanagerimp.hpp" -#include -#include - -#include - #include #include -#include -#include - -#include "../mwbase/environment.hpp" -#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/inputmanager.hpp" -#include "../mwworld/ptr.hpp" -#include "../mwworld/cellstore.hpp" - #include "console.hpp" #include "journalwindow.hpp" #include "charactercreation.hpp" -#include "textinput.hpp" -#include "review.hpp" #include "dialogue.hpp" #include "dialoguehistory.hpp" -#include "mapwindow.hpp" #include "statswindow.hpp" #include "messagebox.hpp" -#include "container.hpp" -#include "inventorywindow.hpp" #include "tooltips.hpp" #include "scrollwindow.hpp" #include "bookwindow.hpp" -#include "list.hpp" #include "hud.hpp" #include "mainmenu.hpp" #include "countdialog.hpp" @@ -48,17 +29,15 @@ #include "loadingscreen.hpp" #include "levelupdialog.hpp" #include "waitdialog.hpp" -#include "spellcreationdialog.hpp" #include "enchantingdialog.hpp" #include "trainingwindow.hpp" -#include "imagebutton.hpp" #include "exposedwindow.hpp" #include "cursor.hpp" -#include "spellicons.hpp" #include "merchantrepair.hpp" #include "repair.hpp" #include "soulgemdialog.hpp" #include "companionwindow.hpp" +#include "inventorywindow.hpp" using namespace MWGui; diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 56868306ac..53ba1b9fd6 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -1,7 +1,5 @@ #include "windowpinnablebase.hpp" -#include "../mwbase/windowmanager.hpp" - #include "exposedwindow.hpp" using namespace MWGui; From 3def2a0f453932c8fed8e83bc2654082e6ab0c46 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 16 Apr 2013 19:16:45 -0700 Subject: [PATCH 0443/1537] Treat the particle random values as the max differential --- components/nifogre/ogrenifloader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 2e77adb082..c5cc45ae9f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -433,11 +433,11 @@ class NIFObjectLoader static void createParticleEmitterAffectors(Ogre::ParticleSystem *partsys, const Nif::NiParticleSystemController *partctrl) { Ogre::ParticleEmitter *emitter = partsys->addEmitter("Nif"); - emitter->setParticleVelocity(partctrl->velocity-partctrl->velocityRandom, - partctrl->velocity+partctrl->velocityRandom); + emitter->setParticleVelocity(partctrl->velocity - partctrl->velocityRandom*0.5f, + partctrl->velocity + partctrl->velocityRandom*0.5f); emitter->setEmissionRate(partctrl->emitRate); - emitter->setTimeToLive(partctrl->lifetime-partctrl->lifetimeRandom, - partctrl->lifetime+partctrl->lifetimeRandom); + emitter->setTimeToLive(partctrl->lifetime - partctrl->lifetimeRandom*0.5f, + partctrl->lifetime + partctrl->lifetimeRandom*0.5f); emitter->setParameter("width", Ogre::StringConverter::toString(partctrl->offsetRandom.x)); emitter->setParameter("height", Ogre::StringConverter::toString(partctrl->offsetRandom.y)); emitter->setParameter("depth", Ogre::StringConverter::toString(partctrl->offsetRandom.z)); From c1ec16986bc396bc611154d992cad25fe3dea503 Mon Sep 17 00:00:00 2001 From: Bret Curtis Date: Wed, 17 Apr 2013 12:04:05 +0200 Subject: [PATCH 0444/1537] add cmake fix for compiling with binutils >= 2.23 which requires explicit linking for dl and Xt --- apps/launcher/CMakeLists.txt | 6 ++++++ apps/openmw/CMakeLists.txt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/apps/launcher/CMakeLists.txt b/apps/launcher/CMakeLists.txt index eb93d71e78..0c93474da9 100644 --- a/apps/launcher/CMakeLists.txt +++ b/apps/launcher/CMakeLists.txt @@ -102,3 +102,9 @@ if (BUILD_WITH_CODE_COVERAGE) add_definitions (--coverage) target_link_libraries(omwlauncher gcov) endif() + +# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream +if (UNIX AND NOT APPLE) +target_link_libraries(omwlauncher dl Xt) +endif() + diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3334e7865c..f4fdcb390e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -122,6 +122,12 @@ if (UNIX AND NOT APPLE) target_link_libraries(openmw ${CMAKE_THREAD_LIBS_INIT}) endif() +# Workaround for binutil => 2.23 problem when linking, should be fixed eventually upstream +if (UNIX AND NOT APPLE) +target_link_libraries(openmw dl Xt) +endif() + + if(APPLE) find_library(CARBON_FRAMEWORK Carbon) find_library(COCOA_FRAMEWORK Cocoa) From 547f77031db127fae46b374c94fccc854d08b067 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Apr 2013 17:05:54 +0200 Subject: [PATCH 0445/1537] Fix crash when disabling objects in a previously loaded cell, then coming back to that cell and leaving again --- apps/openmw/mwrender/actors.cpp | 4 ++++ apps/openmw/mwworld/cellfunctors.hpp | 6 ++++-- apps/openmw/mwworld/scene.cpp | 29 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/actors.cpp b/apps/openmw/mwrender/actors.cpp index 644d3613bd..566b6fa81e 100644 --- a/apps/openmw/mwrender/actors.cpp +++ b/apps/openmw/mwrender/actors.cpp @@ -94,6 +94,9 @@ void Actors::insertActivator (const MWWorld::Ptr& ptr) bool Actors::deleteObject (const MWWorld::Ptr& ptr) { + if (mAllActors.find(ptr) == mAllActors.end()) + return false; + mRendering->removeWaterRippleEmitter (ptr); delete mAllActors[ptr]; @@ -139,6 +142,7 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store) Ogre::SceneNode *base = celliter->second; base->removeAndDestroyAllChildren(); mRend.getScene()->destroySceneNode(base); + mCellSceneNodes.erase(celliter); } } diff --git a/apps/openmw/mwworld/cellfunctors.hpp b/apps/openmw/mwworld/cellfunctors.hpp index 8bba898ce7..4b1f70096a 100644 --- a/apps/openmw/mwworld/cellfunctors.hpp +++ b/apps/openmw/mwworld/cellfunctors.hpp @@ -13,8 +13,8 @@ namespace ESM namespace MWWorld { - /// List all (Ogre-)handles. - struct ListHandles + /// List all (Ogre-)handles, then reset RefData::mBaseNode to 0. + struct ListAndResetHandles { std::vector mHandles; @@ -23,6 +23,8 @@ namespace MWWorld Ogre::SceneNode* handle = data.getBaseNode(); if (handle) mHandles.push_back (handle); + + data.setBaseNode(0); return true; } }; diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 439f761311..b9b0aa19c8 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -76,27 +76,28 @@ namespace MWWorld void Scene::unloadCell (CellStoreCollection::iterator iter) { std::cout << "Unloading cell\n"; - ListHandles functor; + ListAndResetHandles functor; - (*iter)->forEach(functor); + (*iter)->forEach(functor); { // silence annoying g++ warning for (std::vector::const_iterator iter2 (functor.mHandles.begin()); - iter2!=functor.mHandles.end(); ++iter2){ - Ogre::SceneNode* node = *iter2; + iter2!=functor.mHandles.end(); ++iter2) + { + Ogre::SceneNode* node = *iter2; mPhysics->removeObject (node->getName()); } + } - if ((*iter)->mCell->isExterior()) - { - ESM::Land* land = - MWBase::Environment::get().getWorld()->getStore().get().search( - (*iter)->mCell->getGridX(), - (*iter)->mCell->getGridY() - ); - if (land) - mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); - } + if ((*iter)->mCell->isExterior()) + { + ESM::Land* land = + MWBase::Environment::get().getWorld()->getStore().get().search( + (*iter)->mCell->getGridX(), + (*iter)->mCell->getGridY() + ); + if (land) + mPhysics->removeHeightField( (*iter)->mCell->getGridX(), (*iter)->mCell->getGridY() ); } mRendering.removeCell(*iter); From 0341a9e7781342e321744e1976f2a1918521806d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 17 Apr 2013 20:57:22 +0200 Subject: [PATCH 0446/1537] Fix a gcc 4.8 warning --- apps/openmw/mwrender/videoplayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/videoplayer.cpp b/apps/openmw/mwrender/videoplayer.cpp index 2cbc85cd38..87ae8175de 100644 --- a/apps/openmw/mwrender/videoplayer.cpp +++ b/apps/openmw/mwrender/videoplayer.cpp @@ -788,8 +788,8 @@ void VideoState::decode_thread_loop(VideoState *self) // main decode loop while(!self->quit) { - if((self->audio_st >= 0 && self->audioq.size > MAX_AUDIOQ_SIZE) || - (self->video_st >= 0 && self->videoq.size > MAX_VIDEOQ_SIZE)) + if((self->audio_st && self->audioq.size > MAX_AUDIOQ_SIZE) || + (self->video_st && self->videoq.size > MAX_VIDEOQ_SIZE)) { boost::this_thread::sleep(boost::posix_time::milliseconds(10)); continue; From c519fc360ddaeb13872fd761c267123440a88b7e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 00:19:34 +0200 Subject: [PATCH 0447/1537] Move away from fixed record names for body parts --- apps/esmtool/record.cpp | 2 +- apps/openmw/mwgui/race.cpp | 132 +++++++------------------- apps/openmw/mwgui/race.hpp | 7 +- apps/openmw/mwrender/npcanimation.cpp | 109 +++++++++++++-------- components/esm/loadarmo.hpp | 4 +- components/esm/loadbody.cpp | 4 +- components/esm/loadbody.hpp | 6 +- 7 files changed, 118 insertions(+), 146 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e16ade6e24..b7cbbc4eaf 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -439,7 +439,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Name: " << mData.mName << std::endl; + std::cout << " Race: " << mData.mRace << std::endl; std::cout << " Model: " << mData.mModel << std::endl; std::cout << " Type: " << meshTypeLabel(mData.mData.mType) << " (" << (int)mData.mData.mType << ")" << std::endl; diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c031ad6b68..25bae999b5 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -24,36 +24,6 @@ int wrap(int index, int max) else return index; } - -int countParts(const std::string &part, const std::string &race, bool male) -{ - /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - - if (count == 0 && part == "hair") { - count = -1; - do { - ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); - } - while (store.search(prefix + suffix) != 0); - } - return count; -} } RaceDialog::RaceDialog() @@ -61,8 +31,6 @@ RaceDialog::RaceDialog() , mGenderIndex(0) , mFaceIndex(0) , mHairIndex(0) - , mFaceCount(10) - , mHairCount(14) , mCurrentAngle(0) { // Centre dialog @@ -227,67 +195,28 @@ void RaceDialog::onSelectNextGender(MyGUI::Widget*) void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) { - do - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); - while (!isFacePlayable()); + mFaceIndex = wrap(mFaceIndex - 1, mAvailableHeads.size()); updatePreview(); } void RaceDialog::onSelectNextFace(MyGUI::Widget*) { - do - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); - while (!isFacePlayable()); + mFaceIndex = wrap(mFaceIndex + 1, mAvailableHeads.size()); updatePreview(); } void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) { - do - mHairIndex = wrap(mHairIndex - 1, mHairCount); - while (!isHairPlayable()); + mHairIndex = wrap(mHairIndex - 1, mAvailableHairs.size()); updatePreview(); } void RaceDialog::onSelectNextHair(MyGUI::Widget*) { - do - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isHairPlayable()); + mHairIndex = wrap(mHairIndex + 1, mAvailableHairs.size()); updatePreview(); } -bool RaceDialog::isFacePlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(prefix + "head_" + headIndex) == 0) - return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -bool RaceDialog::isHairPlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - if (parts.search(prefix + "hair_" + hairIndex) == 0) - return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) { if (_index == MyGUI::ITEM_NONE) @@ -308,18 +237,41 @@ void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) updateSpellPowers(); } +void RaceDialog::getBodyParts (int part, std::vector& out) +{ + out.clear(); + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator it = store.begin(); it != store.end(); ++it) + { + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) + continue; + if (bodypart.mData.mPart != static_cast(part)) + continue; + if (mGenderIndex != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + bool firstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if (firstPerson) + continue; + if (Misc::StringUtils::ciEqual(bodypart.mRace, mCurrentRaceId)) + out.push_back(bodypart.mId); + } +} + void RaceDialog::recountParts() { - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + getBodyParts(ESM::BodyPart::MP_Hair, mAvailableHairs); + getBodyParts(ESM::BodyPart::MP_Head, mAvailableHeads); mFaceIndex = 0; mHairIndex = 0; - - while (!isHairPlayable()) - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isFacePlayable()) - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); } // update widget content @@ -330,21 +282,9 @@ void RaceDialog::updatePreview() record.mRace = mCurrentRaceId; record.setIsMale(mGenderIndex == 0); - std::string prefix = - "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + record.mHead = mAvailableHeads[mFaceIndex]; + record.mHair = mAvailableHairs[mHairIndex]; - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - record.mHead = prefix + "head_" + headIndex; - record.mHair = prefix + "hair_" + hairIndex; - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(record.mHair) == 0) { - record.mHair = prefix + "hair" + hairIndex; - } mPreview->setPrototype(record); } diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 893c4c90b6..1d48c67cdf 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -76,8 +76,10 @@ namespace MWGui void updatePreview(); void recountParts(); - bool isHairPlayable(); - bool isFacePlayable(); + void getBodyParts (int part, std::vector& out); + + std::vector mAvailableHeads; + std::vector mAvailableHairs; MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; @@ -90,7 +92,6 @@ namespace MWGui std::vector mSpellPowerItems; int mGenderIndex, mFaceIndex, mHairIndex; - int mFaceCount, mHairCount; std::string mCurrentRaceId; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 96220f47d0..ecc0869cc5 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -305,56 +305,83 @@ void NpcAnimation::updateParts(bool forceupdate) if(mViewMode == VM_HeadOnly) return; - static const struct { - ESM::PartReferenceType type; - const char name[2][12]; - } PartTypeList[] = { - { ESM::PRT_Neck, { "neck", "" } }, - { ESM::PRT_Cuirass, { "chest", "" } }, - { ESM::PRT_Groin, { "groin", "" } }, - { ESM::PRT_RHand, { "hand", "hands" } }, - { ESM::PRT_LHand, { "hand", "hands" } }, - { ESM::PRT_RWrist, { "wrist", "" } }, - { ESM::PRT_LWrist, { "wrist", "" } }, - { ESM::PRT_RForearm, { "forearm", "" } }, - { ESM::PRT_LForearm, { "forearm", "" } }, - { ESM::PRT_RUpperarm, { "upper arm", "" } }, - { ESM::PRT_LUpperarm, { "upper arm", "" } }, - { ESM::PRT_RFoot, { "foot", "feet" } }, - { ESM::PRT_LFoot, { "foot", "feet" } }, - { ESM::PRT_RAnkle, { "ankle", "" } }, - { ESM::PRT_LAnkle, { "ankle", "" } }, - { ESM::PRT_RKnee, { "knee", "" } }, - { ESM::PRT_LKnee, { "knee", "" } }, - { ESM::PRT_RLeg, { "upper leg", "" } }, - { ESM::PRT_LLeg, { "upper leg", "" } }, - { ESM::PRT_Tail, { "tail", "" } } - }; + std::map bodypartMap; + bodypartMap[ESM::PRT_Neck] = ESM::BodyPart::MP_Neck; + bodypartMap[ESM::PRT_Cuirass] = ESM::BodyPart::MP_Chest; + bodypartMap[ESM::PRT_Groin] = ESM::BodyPart::MP_Groin; + bodypartMap[ESM::PRT_RHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_LHand] = ESM::BodyPart::MP_Hand; + bodypartMap[ESM::PRT_RWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_LWrist] = ESM::BodyPart::MP_Wrist; + bodypartMap[ESM::PRT_RForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_LForearm] = ESM::BodyPart::MP_Forearm; + bodypartMap[ESM::PRT_RUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_LUpperarm] = ESM::BodyPart::MP_Upperarm; + bodypartMap[ESM::PRT_RFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_LFoot] = ESM::BodyPart::MP_Foot; + bodypartMap[ESM::PRT_RAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_LAnkle] = ESM::BodyPart::MP_Ankle; + bodypartMap[ESM::PRT_RKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_LKnee] = ESM::BodyPart::MP_Knee; + bodypartMap[ESM::PRT_RLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_LLeg] = ESM::BodyPart::MP_Upperleg; + bodypartMap[ESM::PRT_Tail] = ESM::BodyPart::MP_Tail; - const char *ext = (mViewMode == VM_FirstPerson) ? ".1st" : ""; const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for(size_t i = 0;i < sizeof(PartTypeList)/sizeof(PartTypeList[0]);i++) + + const int Flag_Female = 0x01; + const int Flag_FirstPerson = 0x02; + + int flags = 0; + if (!mNpc->isMale()) + flags |= Flag_Female; + if (mViewMode == VM_FirstPerson) + flags |= Flag_FirstPerson; + + // Remember body parts so we only have to search through the store once for each race/gender/viewmode combination + static std::map< std::pair , std::vector > sRaceMapping; + std::string race = Misc::StringUtils::lowerCase(mNpc->mRace); + std::pair thisCombination = std::make_pair(race, flags); + if (sRaceMapping.find(thisCombination) == sRaceMapping.end()) { - if(mPartPriorities[PartTypeList[i].type] < 1) + sRaceMapping[thisCombination].resize(ESM::PRT_Count); + for (int i=0; i &partStore = store.get(); + + for (MWWorld::Store::iterator it = partStore.begin(); it != partStore.end(); ++it) { - const ESM::BodyPart *part = NULL; - const MWWorld::Store &partStore = store.get(); - - if(!mNpc->isMale()) + const ESM::BodyPart& bodypart = *it; + if (bodypart.mData.mFlags & ESM::BodyPart::BPF_NotPlayable) + continue; + if (bodypart.mData.mType != ESM::BodyPart::MT_Skin) { - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[0]+ext); - if(part == 0) - part = partStore.search(mBodyPrefix + "_f_" + PartTypeList[i].name[1]+ext); + continue; } - if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[0]+ext); - if(part == 0) - part = partStore.search(mBodyPrefix + "_m_" + PartTypeList[i].name[1]+ext); + if (!mNpc->isMale() != (bodypart.mData.mFlags & ESM::BodyPart::BPF_Female)) + continue; + if (!Misc::StringUtils::ciEqual(bodypart.mRace, mNpc->mRace)) + continue; - if(part) - addOrReplaceIndividualPart(PartTypeList[i].type, -1,1, "meshes\\"+part->mModel); + bool firstPerson = (bodypart.mId.size() >= 3) + && bodypart.mId[bodypart.mId.size()-3] == '1' + && bodypart.mId[bodypart.mId.size()-2] == 's' + && bodypart.mId[bodypart.mId.size()-1] == 't'; + if (firstPerson != (mViewMode == VM_FirstPerson)) + continue; + for (std::map::iterator bIt = bodypartMap.begin(); bIt != bodypartMap.end(); ++bIt ) + if (bIt->second == bodypart.mData.mPart) + sRaceMapping[thisCombination][bIt->first] = &*it; } } + + for (int part = ESM::PRT_Neck; part < ESM::PRT_Count; ++part) + { + const ESM::BodyPart* bodypart = sRaceMapping[thisCombination][part]; + if (mPartPriorities[part] < 1 && bodypart) + addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); + } } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) diff --git a/components/esm/loadarmo.hpp b/components/esm/loadarmo.hpp index a94ae67353..c18b4486da 100644 --- a/components/esm/loadarmo.hpp +++ b/components/esm/loadarmo.hpp @@ -38,7 +38,9 @@ enum PartReferenceType PRT_RPauldron = 23, PRT_LPauldron = 24, PRT_Weapon = 25, - PRT_Tail = 26 + PRT_Tail = 26, + + PRT_Count = 27 }; // Reference to body parts diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp index 831ad8b641..e95a8a8603 100644 --- a/components/esm/loadbody.cpp +++ b/components/esm/loadbody.cpp @@ -9,13 +9,13 @@ namespace ESM void BodyPart::load(ESMReader &esm) { mModel = esm.getHNString("MODL"); - mName = esm.getHNString("FNAM"); + mRace = esm.getHNString("FNAM"); esm.getHNT(mData, "BYDT", 4); } void BodyPart::save(ESMWriter &esm) { esm.writeHNCString("MODL", mModel); - esm.writeHNCString("FNAM", mName); + esm.writeHNCString("FNAM", mRace); esm.writeHNT("BYDT", mData, 4); } diff --git a/components/esm/loadbody.hpp b/components/esm/loadbody.hpp index c467b36251..3ad9b1b958 100644 --- a/components/esm/loadbody.hpp +++ b/components/esm/loadbody.hpp @@ -27,7 +27,9 @@ struct BodyPart MP_Knee = 11, MP_Upperleg = 12, MP_Clavicle = 13, - MP_Tail = 14 + MP_Tail = 14, + + MP_Count = 15 }; enum Flags @@ -52,7 +54,7 @@ struct BodyPart }; BYDTstruct mData; - std::string mId, mModel, mName; + std::string mId, mModel, mRace; void load(ESMReader &esm); void save(ESMWriter &esm); From 7eee86ab66f8b7fbd33e375418b6bdf44122dedf Mon Sep 17 00:00:00 2001 From: Britt Mathis Date: Wed, 17 Apr 2013 18:56:48 -0400 Subject: [PATCH 0448/1537] No more using namespace --- apps/openmw/mwgui/birth.cpp | 418 ++--- apps/openmw/mwgui/bookwindow.cpp | 261 +-- apps/openmw/mwgui/charactercreation.cpp | 1255 ++++++------- apps/openmw/mwgui/class.cpp | 1599 ++++++++-------- apps/openmw/mwgui/console.cpp | 31 +- apps/openmw/mwgui/container.cpp | 1220 ++++++------ apps/openmw/mwgui/dialogue.cpp | 912 ++++----- apps/openmw/mwgui/dialoguehistory.cpp | 104 +- apps/openmw/mwgui/formatting.cpp | 545 +++--- apps/openmw/mwgui/hud.cpp | 959 +++++----- apps/openmw/mwgui/list.cpp | 296 +-- apps/openmw/mwgui/mapwindow.cpp | 793 ++++---- apps/openmw/mwgui/messagebox.cpp | 747 ++++---- apps/openmw/mwgui/race.cpp | 822 ++++----- apps/openmw/mwgui/review.cpp | 658 +++---- apps/openmw/mwgui/scrollwindow.cpp | 128 +- apps/openmw/mwgui/statswindow.cpp | 1021 +++++----- apps/openmw/mwgui/textinput.cpp | 121 +- apps/openmw/mwgui/tooltips.cpp | 1416 +++++++------- apps/openmw/mwgui/widgets.cpp | 1676 ++++++++--------- apps/openmw/mwgui/windowmanagerimp.cpp | 2145 +++++++++++----------- apps/openmw/mwgui/windowpinnablebase.cpp | 39 +- 22 files changed, 8609 insertions(+), 8557 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index 9c3ebdc7dc..9656067097 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -9,237 +9,239 @@ #include "widgets.hpp" -using namespace MWGui; -using namespace Widgets; - namespace { -bool sortBirthSigns(const std::pair& left, const std::pair& right) -{ - return left.second->mName.compare (right.second->mName) < 0; -} + bool sortBirthSigns(const std::pair& left, const std::pair& right) + { + return left.second->mName.compare (right.second->mName) < 0; + } } -BirthDialog::BirthDialog() - : WindowModal("openmw_chargen_birth.layout") +namespace MWGui { - // Centre dialog - center(); - getWidget(mSpellArea, "SpellArea"); + BirthDialog::BirthDialog() + : WindowModal("openmw_chargen_birth.layout") + { + // Centre dialog + center(); - getWidget(mBirthImage, "BirthsignImage"); + getWidget(mSpellArea, "SpellArea"); - getWidget(mBirthList, "BirthsignList"); - mBirthList->setScrollVisible(true); - mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + getWidget(mBirthImage, "BirthsignImage"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); + getWidget(mBirthList, "BirthsignList"); + mBirthList->setScrollVisible(true); + mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListMouseItemActivate += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); + mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - updateBirths(); - updateSpells(); -} - -void BirthDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); -void BirthDialog::open() -{ - WindowModal::open(); - updateBirths(); - updateSpells(); -} + updateBirths(); + updateSpells(); + } - -void BirthDialog::setBirthId(const std::string &birthId) -{ - mCurrentBirthId = birthId; - mBirthList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mBirthList->getItemCount(); - for (size_t i = 0; i < count; ++i) + void BirthDialog::setNextButtonShow(bool shown) { - if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void BirthDialog::open() + { + WindowModal::open(); + updateBirths(); + updateSpells(); + } + + + void BirthDialog::setBirthId(const std::string &birthId) + { + mCurrentBirthId = birthId; + mBirthList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mBirthList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mBirthList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; - } - } - - updateSpells(); -} - -// widget controls - -void BirthDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void BirthDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - const std::string *birthId = mBirthList->getItemDataAt(_index); - if (boost::iequals(mCurrentBirthId, *birthId)) - return; - - mCurrentBirthId = *birthId; - updateSpells(); -} - -// update widget content - -void BirthDialog::updateBirths() -{ - mBirthList->removeAllItems(); - - const MWWorld::Store &signs = - MWBase::Environment::get().getWorld()->getStore().get(); - - // sort by name - std::vector < std::pair > birthSigns; - - MWWorld::Store::iterator it = signs.begin(); - for (; it != signs.end(); ++it) - { - birthSigns.push_back(std::make_pair(it->mId, &(*it))); - } - std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); - - int index = 0; - for (std::vector >::const_iterator it2 = birthSigns.begin(); - it2 != birthSigns.end(); ++it2, ++index) - { - mBirthList->addItem(it2->second->mName, it2->first); - if (mCurrentBirthId.empty()) - { - mBirthList->setIndexSelected(index); - mCurrentBirthId = it2->first; - } - else if (boost::iequals(it2->first, mCurrentBirthId)) - { - mBirthList->setIndexSelected(index); - } - } -} - -void BirthDialog::updateSpells() -{ - for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSpellItems.clear(); - - if (mCurrentBirthId.empty()) - return; - - MWSpellPtr spellWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::BirthSign *birth = - store.get().find(mCurrentBirthId); - - std::string texturePath = std::string("textures\\") + birth->mTexture; - fixTexturePath(texturePath); - mBirthImage->setImageTexture(texturePath); - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = birth->mPowers.mList.begin(); - std::vector::const_iterator end = birth->mPowers.mList.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->mData.mType); - 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); - } - - int i = 0; - - struct { - const std::vector &spells; - const char *label; - } - categories[3] = { - {abilities, "sBirthsignmenu1"}, - {powers, "sPowers"}, - {spells, "sBirthsignmenu2"} - }; - - for (int category = 0; category < 3; ++category) - { - if (!categories[category].spells.empty()) - { - MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); - label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); - mSpellItems.push_back(label); - coord.top += lineHeight; - - std::vector::const_iterator end = categories[category].spells.end(); - for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + if (boost::iequals(*mBirthList->getItemDataAt(i), birthId)) { - const std::string &spellId = *it; - spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); - spellWidget->setSpellId(spellId); + mBirthList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } + } - mSpellItems.push_back(spellWidget); - coord.top += lineHeight; + 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(mSpellItems, mSpellArea, spellCoord, (category == 0) ? MWEffectList::EF_Constant : 0); - coord.top = spellCoord.top; + // widget controls - ++i; + void BirthDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(mBirthList->getIndexSelected() == MyGUI::ITEM_NONE) + return; + eventDone(this); + } + + void BirthDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void BirthDialog::onSelectBirth(MyGUI::ListBox* _sender, size_t _index) + { + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + const std::string *birthId = mBirthList->getItemDataAt(_index); + if (boost::iequals(mCurrentBirthId, *birthId)) + return; + + mCurrentBirthId = *birthId; + updateSpells(); + } + + // update widget content + + void BirthDialog::updateBirths() + { + mBirthList->removeAllItems(); + + const MWWorld::Store &signs = + MWBase::Environment::get().getWorld()->getStore().get(); + + // sort by name + std::vector < std::pair > birthSigns; + + MWWorld::Store::iterator it = signs.begin(); + for (; it != signs.end(); ++it) + { + birthSigns.push_back(std::make_pair(it->mId, &(*it))); + } + std::sort(birthSigns.begin(), birthSigns.end(), sortBirthSigns); + + int index = 0; + for (std::vector >::const_iterator it2 = birthSigns.begin(); + it2 != birthSigns.end(); ++it2, ++index) + { + mBirthList->addItem(it2->second->mName, it2->first); + if (mCurrentBirthId.empty()) + { + mBirthList->setIndexSelected(index); + mCurrentBirthId = it2->first; + } + else if (boost::iequals(it2->first, mCurrentBirthId)) + { + mBirthList->setIndexSelected(index); } } } + + void BirthDialog::updateSpells() + { + for (std::vector::iterator it = mSpellItems.begin(); it != mSpellItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSpellItems.clear(); + + if (mCurrentBirthId.empty()) + return; + + Widgets::MWSpellPtr spellWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord(0, 0, mSpellArea->getWidth(), 18); + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *birth = + store.get().find(mCurrentBirthId); + + std::string texturePath = std::string("textures\\") + birth->mTexture; + Widgets::fixTexturePath(texturePath); + mBirthImage->setImageTexture(texturePath); + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = birth->mPowers.mList.begin(); + std::vector::const_iterator end = birth->mPowers.mList.end(); + for (; it != end; ++it) + { + const std::string &spellId = *it; + const ESM::Spell *spell = store.get().search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->mData.mType); + 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); + } + + int i = 0; + + struct { + const std::vector &spells; + const char *label; + } + categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + if (!categories[category].spells.empty()) + { + MyGUI::TextBox* label = mSpellArea->createWidget("SandBrightText", coord, MyGUI::Align::Default, std::string("Label")); + label->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString(categories[category].label, "")); + mSpellItems.push_back(label); + coord.top += lineHeight; + + std::vector::const_iterator end = categories[category].spells.end(); + for (std::vector::const_iterator it = categories[category].spells.begin(); it != end; ++it) + { + const std::string &spellId = *it; + spellWidget = mSpellArea->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("Spell") + boost::lexical_cast(i)); + spellWidget->setSpellId(spellId); + + mSpellItems.push_back(spellWidget); + coord.top += lineHeight; + + 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(mSpellItems, mSpellArea, spellCoord, (category == 0) ? Widgets::MWEffectList::EF_Constant : 0); + coord.top = spellCoord.top; + + ++i; + } + } + } + } + } diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index ce74c48593..6d44e9d2c5 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -12,148 +12,151 @@ #include "formatting.hpp" -using namespace MWGui; - -BookWindow::BookWindow () - : WindowBase("openmw_book.layout") - , mTakeButtonShow(true) - , mTakeButtonAllowed(true) +namespace MWGui { - 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); - - 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) + BookWindow::BookWindow () + : WindowBase("openmw_book.layout") + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mPages.clear(); -} + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onCloseButtonClicked); -void BookWindow::open (MWWorld::Ptr book) -{ - mBook = book; + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onTakeButtonClicked); - clearPages(); - mCurrentPage = 0; + getWidget(mNextPageButton, "NextPageBTN"); + mNextPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onNextPageButtonClicked); - MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + getWidget(mPrevPageButton, "PrevPageBTN"); + mPrevPageButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BookWindow::onPrevPageButtonClicked); - MWWorld::LiveCellRef *ref = mBook.get(); + getWidget(mLeftPageNumber, "LeftPageNumber"); + getWidget(mRightPageNumber, "RightPageNumber"); - BookTextParser parser; - std::vector results = parser.split(ref->mBase->mText, mLeftPage->getSize().width, mLeftPage->getSize().height); + getWidget(mLeftPage, "LeftPage"); + getWidget(mRightPage, "RightPage"); - 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; + center(); } - updatePages(); - - setTakeButtonShow(true); -} - -void BookWindow::setTakeButtonShow(bool show) -{ - mTakeButtonShow = show; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void BookWindow::setInventoryAllowed(bool allowed) -{ - mTakeButtonAllowed = allowed; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -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().getWindowManager()->removeGuiMode(GM_Book); -} - -void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); - - MWWorld::ActionTake take(mBook); - take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); -} - -void BookWindow::onNextPageButtonClicked (MyGUI::Widget* sender) -{ - if ((mCurrentPage+1)*2 < mPages.size()) + void BookWindow::clearPages() { - 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 + for (std::vector::iterator it=mPages.begin(); + it!=mPages.end(); ++it) { - (*it)->setVisible(false); + MyGUI::Gui::getInstance().destroyWidget(*it); } - ++i; + mPages.clear(); } + + void BookWindow::open (MWWorld::Ptr book) + { + mBook = book; + + clearPages(); + mCurrentPage = 0; + + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + + MWWorld::LiveCellRef *ref = mBook.get(); + + BookTextParser parser; + std::vector results = parser.split(ref->mBase->mText, 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(); + + setTakeButtonShow(true); + } + + void BookWindow::setTakeButtonShow(bool show) + { + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void BookWindow::setInventoryAllowed(bool allowed) + { + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + 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().getWindowManager()->removeGuiMode(GM_Book); + } + + void BookWindow::onTakeButtonClicked (MyGUI::Widget* sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); + + MWWorld::ActionTake take(mBook); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Book); + } + + 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/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 28f6d13ee2..fc8c24484e 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -43,682 +43,685 @@ namespace }; } -using namespace MWGui; - -CharacterCreation::CharacterCreation() - : mNameDialog(0) - , mRaceDialog(0) - , mClassChoiceDialog(0) - , mGenerateClassQuestionDialog(0) - , mGenerateClassResultDialog(0) - , mPickClassDialog(0) - , mCreateClassDialog(0) - , mBirthSignDialog(0) - , mReviewDialog(0) - , mGenerateClassStep(0) +namespace MWGui { - mCreationStage = CSE_NotStarted; -} -void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - if (mReviewDialog) + CharacterCreation::CharacterCreation() + : mNameDialog(0) + , mRaceDialog(0) + , mClassChoiceDialog(0) + , mGenerateClassQuestionDialog(0) + , mGenerateClassResultDialog(0) + , mPickClassDialog(0) + , mCreateClassDialog(0) + , mBirthSignDialog(0) + , mReviewDialog(0) + , mGenerateClassStep(0) { - static const char *ids[] = + mCreationStage = CSE_NotStarted; + } + + void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat& value) + { + if (mReviewDialog) { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 + 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) + { + case GM_Name: + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + mNameDialog = new TextInputDialog(); + mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); + mNameDialog->setTextInput(mPlayerName); + mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); + mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); + mNameDialog->setVisible(true); + break; + + case GM_Race: + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + mRaceDialog = new RaceDialog(); + mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); + mRaceDialog->setRaceId(mPlayerRaceId); + mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); + mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); + mRaceDialog->setVisible(true); + if (mCreationStage < CSE_NameChosen) + mCreationStage = CSE_NameChosen; + break; + + case GM_Class: + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + mClassChoiceDialog = new ClassChoiceDialog(); + mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); + mClassChoiceDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + + case GM_ClassPick: + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + mPickClassDialog = new PickClassDialog(); + mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mPickClassDialog->setClassId(mPlayerClass.mName); + mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); + mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); + mPickClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + + case GM_Birth: + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + mBirthSignDialog = new BirthDialog(); + mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); + mBirthSignDialog->setBirthId(mPlayerBirthSignId); + mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); + mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); + mBirthSignDialog->setVisible(true); + if (mCreationStage < CSE_ClassChosen) + mCreationStage = CSE_ClassChosen; + break; + + case GM_ClassCreate: + MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); + mCreateClassDialog = 0; + mCreateClassDialog = new CreateClassDialog(); + mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); + mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); + mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); + mCreateClassDialog->setVisible(true); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_ClassGenerate: + mGenerateClassStep = 0; + mGenerateClass = ""; + mGenerateClassSpecializations[0] = 0; + mGenerateClassSpecializations[1] = 0; + mGenerateClassSpecializations[2] = 0; + showClassQuestionDialog(); + if (mCreationStage < CSE_RaceChosen) + mCreationStage = CSE_RaceChosen; + break; + case GM_Review: + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mReviewDialog = new ReviewDialog(); + mReviewDialog->setPlayerName(mPlayerName); + mReviewDialog->setRace(mPlayerRaceId); + mReviewDialog->setClass(mPlayerClass); + mReviewDialog->setBirthSign(mPlayerBirthSignId); + + mReviewDialog->setHealth(mPlayerHealth); + mReviewDialog->setMagicka(mPlayerMagicka); + mReviewDialog->setFatigue(mPlayerFatigue); + + { + std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); + for (std::map >::iterator it = attributes.begin(); + it != attributes.end(); ++it) + { + mReviewDialog->setAttribute(static_cast (it->first), it->second); + } + } + + { + std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); + for (std::map >::iterator it = skills.begin(); + it != skills.end(); ++it) + { + mReviewDialog->setSkillValue(static_cast (it->first), it->second); + } + mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); + } + + mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); + mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); + mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); + mReviewDialog->setVisible(true); + if (mCreationStage < CSE_BirthSignChosen) + mCreationStage = CSE_BirthSignChosen; + break; + } + } + + void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) + { + mPlayerHealth = value; + } + + void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) + { + mPlayerMagicka = value; + } + + void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) + { + mPlayerFatigue = value; + } + + void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + + void CharacterCreation::onReviewDialogBack() + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + + void CharacterCreation::onReviewActivateDialog(int parDialog) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); + mReviewDialog = 0; + mCreationStage = CSE_ReviewNext; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + switch(parDialog) + { + case ReviewDialog::NAME_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + break; + case ReviewDialog::RACE_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + break; + case ReviewDialog::CLASS_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + break; + case ReviewDialog::BIRTHSIGN_DIALOG: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); }; - - 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) + void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) { - if (id == "HBar") + if (mPickClassDialog) { - mReviewDialog->setHealth (value); - } - else if (id == "MBar") - { - mReviewDialog->setMagicka (value); - } - else if (id == "FBar") - { - mReviewDialog->setFatigue (value); - } - } -} + const std::string &classId = mPickClassDialog->getClassId(); + if (!classId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); -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) - { - case GM_Name: - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - mNameDialog = new TextInputDialog(); - mNameDialog->setTextLabel(MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "Name")); - mNameDialog->setTextInput(mPlayerName); - mNameDialog->setNextButtonShow(mCreationStage >= CSE_NameChosen); - mNameDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onNameDialogDone); - mNameDialog->setVisible(true); - break; - - case GM_Race: - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - mRaceDialog = new RaceDialog(); - mRaceDialog->setNextButtonShow(mCreationStage >= CSE_RaceChosen); - mRaceDialog->setRaceId(mPlayerRaceId); - mRaceDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogDone); - mRaceDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onRaceDialogBack); - mRaceDialog->setVisible(true); - if (mCreationStage < CSE_NameChosen) - mCreationStage = CSE_NameChosen; - break; - - case GM_Class: - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - mClassChoiceDialog = new ClassChoiceDialog(); - mClassChoiceDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassChoice); - mClassChoiceDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - - case GM_ClassPick: + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(classId); + if (klass) + { + mPlayerClass = *klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + } MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); mPickClassDialog = 0; - mPickClassDialog = new PickClassDialog(); - mPickClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mPickClassDialog->setClassId(mPlayerClass.mName); - mPickClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogDone); - mPickClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onPickClassDialogBack); - mPickClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; + } - case GM_Birth: + //TODO This bit gets repeated a few times; wrap it in a function + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + else + { + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onPickClassDialogBack() + { + if (mPickClassDialog) + { + const std::string classId = mPickClassDialog->getClassId(); + if (!classId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); + MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); + mPickClassDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onClassChoice(int _index) + { + MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); + mClassChoiceDialog = 0; + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + switch(_index) + { + case ClassChoiceDialog::Class_Generate: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); + break; + case ClassChoiceDialog::Class_Pick: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); + break; + case ClassChoiceDialog::Class_Create: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); + break; + case ClassChoiceDialog::Class_Back: + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + break; + + }; + } + + void CharacterCreation::onNameDialogDone(WindowBase* parWindow) + { + if (mNameDialog) + { + mPlayerName = mNameDialog->getTextInput(); + MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); + MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); + MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); + mNameDialog = 0; + } + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_NameChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + } + else + { + mCreationStage = CSE_NameChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onRaceDialogBack() + { + if (mRaceDialog) + { + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); + } + + void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) + { + if (mRaceDialog) + { + const ESM::NPC &data = mRaceDialog->getResult(); + mPlayerRaceId = data.mRace; + if (!mPlayerRaceId.empty()) { + MWBase::Environment::get().getMechanicsManager()->setPlayerRace( + data.mRace, + data.isMale(), + data.mHead, + data.mHair + ); + } + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); + + MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); + mRaceDialog = 0; + } + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_RaceChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + else + { + mCreationStage = CSE_RaceChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) + { + if (mBirthSignDialog) + { + mPlayerBirthSignId = mBirthSignDialog->getBirthId(); + if (!mPlayerBirthSignId.empty()) + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); mBirthSignDialog = 0; - mBirthSignDialog = new BirthDialog(); - mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); - mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); - mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); - mBirthSignDialog->setVisible(true); - if (mCreationStage < CSE_ClassChosen) - mCreationStage = CSE_ClassChosen; - break; + } + + if (mCreationStage >= CSE_BirthSignChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else + { + mCreationStage = CSE_BirthSignChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + void CharacterCreation::onBirthSignDialogBack() + { + if (mBirthSignDialog) + { + MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); + MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); + mBirthSignDialog = 0; + } + + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + } + + void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) + { + if (mCreateClassDialog) + { + ESM::Class klass; + klass.mName = mCreateClassDialog->getName(); + klass.mDescription = mCreateClassDialog->getDescription(); + klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); + klass.mData.mIsPlayable = 0x1; + + std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); + assert(attributes.size() == 2); + klass.mData.mAttribute[0] = attributes[0]; + klass.mData.mAttribute[1] = attributes[1]; + + std::vector majorSkills = mCreateClassDialog->getMajorSkills(); + std::vector minorSkills = mCreateClassDialog->getMinorSkills(); + assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); + assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); + for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) + { + klass.mData.mSkills[i][1] = majorSkills[i]; + klass.mData.mSkills[i][0] = minorSkills[i]; + } + + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); + mPlayerClass = klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - case GM_ClassCreate: MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - mCreateClassDialog = new CreateClassDialog(); - mCreateClassDialog->setNextButtonShow(mCreationStage >= CSE_ClassChosen); - mCreateClassDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogDone); - mCreateClassDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onCreateClassDialogBack); - mCreateClassDialog->setVisible(true); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_ClassGenerate: - mGenerateClassStep = 0; - mGenerateClass = ""; - mGenerateClassSpecializations[0] = 0; - mGenerateClassSpecializations[1] = 0; - mGenerateClassSpecializations[2] = 0; - showClassQuestionDialog(); - if (mCreationStage < CSE_RaceChosen) - mCreationStage = CSE_RaceChosen; - break; - case GM_Review: - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mReviewDialog = new ReviewDialog(); - mReviewDialog->setPlayerName(mPlayerName); - mReviewDialog->setRace(mPlayerRaceId); - mReviewDialog->setClass(mPlayerClass); - mReviewDialog->setBirthSign(mPlayerBirthSignId); + } - mReviewDialog->setHealth(mPlayerHealth); - mReviewDialog->setMagicka(mPlayerMagicka); - mReviewDialog->setFatigue(mPlayerFatigue); - - { - std::map > attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (std::map >::iterator it = attributes.begin(); - it != attributes.end(); ++it) - { - mReviewDialog->setAttribute(static_cast (it->first), it->second); - } - } - - { - std::map > skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (std::map >::iterator it = skills.begin(); - it != skills.end(); ++it) - { - mReviewDialog->setSkillValue(static_cast (it->first), it->second); - } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); - } - - mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); - mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); - mReviewDialog->eventActivateDialog += MyGUI::newDelegate(this, &CharacterCreation::onReviewActivateDialog); - mReviewDialog->setVisible(true); - if (mCreationStage < CSE_BirthSignChosen) - mCreationStage = CSE_BirthSignChosen; - break; - } -} - -void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) -{ - mPlayerHealth = value; -} - -void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) -{ - mPlayerMagicka = value; -} - -void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) -{ - mPlayerFatigue = value; -} - -void CharacterCreation::onReviewDialogDone(WindowBase* parWindow) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); -} - -void CharacterCreation::onReviewDialogBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); -} - -void CharacterCreation::onReviewActivateDialog(int parDialog) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mReviewDialog); - mReviewDialog = 0; - mCreationStage = CSE_ReviewNext; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - switch(parDialog) - { - case ReviewDialog::NAME_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); - break; - case ReviewDialog::RACE_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - break; - case ReviewDialog::CLASS_DIALOG: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - break; - case ReviewDialog::BIRTHSIGN_DIALOG: + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - }; -} - -void CharacterCreation::onPickClassDialogDone(WindowBase* parWindow) -{ - if (mPickClassDialog) - { - const std::string &classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - - const ESM::Class *klass = - MWBase::Environment::get().getWorld()->getStore().get().find(classId); - if (klass) + } + else { - mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); } - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; } - //TODO This bit gets repeated a few times; wrap it in a function - if (mCreationStage == CSE_ReviewNext) + void CharacterCreation::onCreateClassDialogBack() { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onPickClassDialogBack() -{ - if (mPickClassDialog) - { - const std::string classId = mPickClassDialog->getClassId(); - if (!classId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(classId); - MWBase::Environment::get().getWindowManager()->removeDialog(mPickClassDialog); - mPickClassDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onClassChoice(int _index) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mClassChoiceDialog); - mClassChoiceDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - - switch(_index) - { - case ClassChoiceDialog::Class_Generate: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassGenerate); - break; - case ClassChoiceDialog::Class_Pick: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassPick); - break; - case ClassChoiceDialog::Class_Create: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_ClassCreate); - break; - case ClassChoiceDialog::Class_Back: - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - break; - - }; -} - -void CharacterCreation::onNameDialogDone(WindowBase* parWindow) -{ - if (mNameDialog) - { - mPlayerName = mNameDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->setValue("name", mPlayerName); - MWBase::Environment::get().getMechanicsManager()->setPlayerName(mPlayerName); - MWBase::Environment::get().getWindowManager()->removeDialog(mNameDialog); - mNameDialog = 0; - } - - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_NameChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); - } - else - { - mCreationStage = CSE_NameChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onRaceDialogBack() -{ - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Name); -} - -void CharacterCreation::onRaceDialogDone(WindowBase* parWindow) -{ - if (mRaceDialog) - { - const ESM::NPC &data = mRaceDialog->getResult(); - mPlayerRaceId = data.mRace; - if (!mPlayerRaceId.empty()) { - MWBase::Environment::get().getMechanicsManager()->setPlayerRace( - data.mRace, - data.isMale(), - data.mHead, - data.mHair - ); - } - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mRaceDialog); - mRaceDialog = 0; - } - - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_RaceChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - } - else - { - mCreationStage = CSE_RaceChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) -{ - if (mBirthSignDialog) - { - mPlayerBirthSignId = mBirthSignDialog->getBirthId(); - if (!mPlayerBirthSignId.empty()) - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } - - if (mCreationStage >= CSE_BirthSignChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else - { - mCreationStage = CSE_BirthSignChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onBirthSignDialogBack() -{ - if (mBirthSignDialog) - { - MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mBirthSignDialog->getBirthId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mBirthSignDialog); - mBirthSignDialog = 0; - } - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onCreateClassDialogDone(WindowBase* parWindow) -{ - if (mCreateClassDialog) - { - ESM::Class klass; - klass.mName = mCreateClassDialog->getName(); - klass.mDescription = mCreateClassDialog->getDescription(); - klass.mData.mSpecialization = mCreateClassDialog->getSpecializationId(); - klass.mData.mIsPlayable = 0x1; - - std::vector attributes = mCreateClassDialog->getFavoriteAttributes(); - assert(attributes.size() == 2); - klass.mData.mAttribute[0] = attributes[0]; - klass.mData.mAttribute[1] = attributes[1]; - - std::vector majorSkills = mCreateClassDialog->getMajorSkills(); - std::vector minorSkills = mCreateClassDialog->getMinorSkills(); - assert(majorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); - assert(minorSkills.size() >= sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0])); - for (size_t i = 0; i < sizeof(klass.mData.mSkills)/sizeof(klass.mData.mSkills[0]); ++i) - { - klass.mData.mSkills[i][1] = majorSkills[i]; - klass.mData.mSkills[i][0] = minorSkills[i]; - } - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(klass); - mPlayerClass = klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(klass); - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); mCreateClassDialog = 0; - } - if (mCreationStage == CSE_ReviewNext) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} - -void CharacterCreation::onCreateClassDialogBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mCreateClassDialog); - mCreateClassDialog = 0; - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onClassQuestionChosen(int _index) -{ - MWBase::Environment::get().getSoundManager()->stopSay(); - - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); - mGenerateClassQuestionDialog = 0; - - if (_index < 0 || _index >= 3) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - return; } - ESM::Class::Specialization specialization = mSpecializations[_index]; - if (specialization == ESM::Class::Stealth) - ++mGenerateClassSpecializations[0]; - else if (specialization == ESM::Class::Combat) - ++mGenerateClassSpecializations[1]; - else if (specialization == ESM::Class::Magic) - ++mGenerateClassSpecializations[2]; - ++mGenerateClassStep; - showClassQuestionDialog(); -} - -void CharacterCreation::showClassQuestionDialog() -{ - if (mGenerateClassStep == 10) + void CharacterCreation::onClassQuestionChosen(int _index) { - static boost::array classes = { { - {"Acrobat", {6, 2, 2}}, - {"Agent", {6, 1, 3}}, - {"Archer", {3, 5, 2}}, - {"Archer", {5, 5, 0}}, - {"Assassin", {6, 3, 1}}, - {"Barbarian", {3, 6, 1}}, - {"Bard", {3, 3, 3}}, - {"Battlemage", {1, 3, 6}}, - {"Crusader", {1, 6, 3}}, - {"Healer", {3, 1, 6}}, - {"Knight", {2, 6, 2}}, - {"Monk", {5, 3, 2}}, - {"Nightblade", {4, 2, 4}}, - {"Pilgrim", {5, 2, 3}}, - {"Rogue", {3, 4, 3}}, - {"Rogue", {4, 4, 2}}, - {"Rogue", {5, 4, 1}}, - {"Scout", {2, 5, 3}}, - {"Sorcerer", {2, 2, 6}}, - {"Spellsword", {2, 4, 4}}, - {"Spellsword", {5, 1, 4}}, - {"Witchhunter", {2, 3, 5}}, - {"Witchhunter", {5, 0, 5}} - } }; + MWBase::Environment::get().getSoundManager()->stopSay(); - int match = -1; - for (unsigned i = 0; i < classes.size(); ++i) + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + + if (_index < 0 || _index >= 3) { - if (mGenerateClassSpecializations[0] == classes[i].points[0] && - mGenerateClassSpecializations[1] == classes[i].points[1] && - mGenerateClassSpecializations[2] == classes[i].points[2]) - { - match = i; - mGenerateClass = classes[i].id; - break; - } + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + return; } - if (match == -1) + ESM::Class::Specialization specialization = mSpecializations[_index]; + if (specialization == ESM::Class::Stealth) + ++mGenerateClassSpecializations[0]; + else if (specialization == ESM::Class::Combat) + ++mGenerateClassSpecializations[1]; + else if (specialization == ESM::Class::Magic) + ++mGenerateClassSpecializations[2]; + ++mGenerateClassStep; + showClassQuestionDialog(); + } + + void CharacterCreation::showClassQuestionDialog() + { + if (mGenerateClassStep == 10) { - if (mGenerateClassSpecializations[0] >= 7) - mGenerateClass = "Thief"; - else if (mGenerateClassSpecializations[1] >= 7) - mGenerateClass = "Warrior"; - else if (mGenerateClassSpecializations[2] >= 7) - mGenerateClass = "Mage"; - else + static boost::array classes = { { + {"Acrobat", {6, 2, 2}}, + {"Agent", {6, 1, 3}}, + {"Archer", {3, 5, 2}}, + {"Archer", {5, 5, 0}}, + {"Assassin", {6, 3, 1}}, + {"Barbarian", {3, 6, 1}}, + {"Bard", {3, 3, 3}}, + {"Battlemage", {1, 3, 6}}, + {"Crusader", {1, 6, 3}}, + {"Healer", {3, 1, 6}}, + {"Knight", {2, 6, 2}}, + {"Monk", {5, 3, 2}}, + {"Nightblade", {4, 2, 4}}, + {"Pilgrim", {5, 2, 3}}, + {"Rogue", {3, 4, 3}}, + {"Rogue", {4, 4, 2}}, + {"Rogue", {5, 4, 1}}, + {"Scout", {2, 5, 3}}, + {"Sorcerer", {2, 2, 6}}, + {"Spellsword", {2, 4, 4}}, + {"Spellsword", {5, 1, 4}}, + {"Witchhunter", {2, 3, 5}}, + {"Witchhunter", {5, 0, 5}} + } }; + + int match = -1; + for (unsigned i = 0; i < classes.size(); ++i) { - std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl; - mGenerateClass = "Thief"; + if (mGenerateClassSpecializations[0] == classes[i].points[0] && + mGenerateClassSpecializations[1] == classes[i].points[1] && + mGenerateClassSpecializations[2] == classes[i].points[2]) + { + match = i; + mGenerateClass = classes[i].id; + break; + } } + + if (match == -1) + { + if (mGenerateClassSpecializations[0] >= 7) + mGenerateClass = "Thief"; + else if (mGenerateClassSpecializations[1] >= 7) + mGenerateClass = "Warrior"; + else if (mGenerateClassSpecializations[2] >= 7) + mGenerateClass = "Mage"; + else + { + std::cerr << "Failed to deduce class from chosen answers in generate class dialog" << std::endl; + mGenerateClass = "Thief"; + } + } + + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + + mGenerateClassResultDialog = new GenerateClassResultDialog(); + mGenerateClassResultDialog->setClassId(mGenerateClass); + mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); + mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); + mGenerateClassResultDialog->setVisible(true); + return; } + if (mGenerateClassStep > 10) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + return; + } + + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); + mGenerateClassQuestionDialog = 0; + + mGenerateClassQuestionDialog = new InfoBoxDialog(); + + InfoBoxDialog::ButtonList buttons; + mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); + buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); + mGenerateClassQuestionDialog->setButtons(buttons); + mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); + mGenerateClassQuestionDialog->setVisible(true); + + MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); + } + + void CharacterCreation::onGenerateClassBack() + { MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); mGenerateClassResultDialog = 0; - mGenerateClassResultDialog = new GenerateClassResultDialog(); - mGenerateClassResultDialog->setClassId(mGenerateClass); - mGenerateClassResultDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassBack); - mGenerateClassResultDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onGenerateClassDone); - mGenerateClassResultDialog->setVisible(true); - return; - } + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - if (mGenerateClassStep > 10) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); - return; } - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassQuestionDialog); - mGenerateClassQuestionDialog = 0; - - mGenerateClassQuestionDialog = new InfoBoxDialog(); - - InfoBoxDialog::ButtonList buttons; - mGenerateClassQuestionDialog->setText(sGenerateClassSteps(mGenerateClassStep).mText); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[0]); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[1]); - buttons.push_back(sGenerateClassSteps(mGenerateClassStep).mButtons[2]); - mGenerateClassQuestionDialog->setButtons(buttons); - mGenerateClassQuestionDialog->eventButtonSelected += MyGUI::newDelegate(this, &CharacterCreation::onClassQuestionChosen); - mGenerateClassQuestionDialog->setVisible(true); - - MWBase::Environment::get().getSoundManager()->say(sGenerateClassSteps(mGenerateClassStep).mSound); -} - -void CharacterCreation::onGenerateClassBack() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); -} - -void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); - mGenerateClassResultDialog = 0; - - MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); - - const ESM::Class *klass = - MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); - - mPlayerClass = *klass; - MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); - - if (mCreationStage == CSE_ReviewNext) + void CharacterCreation::onGenerateClassDone(WindowBase* parWindow) { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); - } - else if (mCreationStage >= CSE_ClassChosen) - { - MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); - } - else - { - mCreationStage = CSE_ClassChosen; - MWBase::Environment::get().getWindowManager()->popGuiMode(); - } -} + MWBase::Environment::get().getWindowManager()->removeDialog(mGenerateClassResultDialog); + mGenerateClassResultDialog = 0; + + MWBase::Environment::get().getMechanicsManager()->setPlayerClass(mGenerateClass); + + const ESM::Class *klass = + MWBase::Environment::get().getWorld()->getStore().get().find(mGenerateClass); + + mPlayerClass = *klass; + MWBase::Environment::get().getWindowManager()->setPlayerClass(mPlayerClass); + + if (mCreationStage == CSE_ReviewNext) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Review); + } + else if (mCreationStage >= CSE_ClassChosen) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + } + else + { + mCreationStage = CSE_ClassChosen; + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } + } + + CharacterCreation::~CharacterCreation() + { + delete mNameDialog; + delete mRaceDialog; + delete mClassChoiceDialog; + delete mGenerateClassQuestionDialog; + delete mGenerateClassResultDialog; + delete mPickClassDialog; + delete mCreateClassDialog; + delete mBirthSignDialog; + delete mReviewDialog; + } -CharacterCreation::~CharacterCreation() -{ - delete mNameDialog; - delete mRaceDialog; - delete mClassChoiceDialog; - delete mGenerateClassQuestionDialog; - delete mGenerateClassResultDialog; - delete mPickClassDialog; - delete mCreateClassDialog; - delete mBirthSignDialog; - delete mReviewDialog; } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e4d32c933b..ab81038689 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -11,870 +11,873 @@ #undef min #undef max -using namespace MWGui; - -/* GenerateClassResultDialog */ - -GenerateClassResultDialog::GenerateClassResultDialog() - : WindowModal("openmw_chargen_generate_class_result.layout") +namespace MWGui { - // Centre dialog - center(); - setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); + /* GenerateClassResultDialog */ - getWidget(mClassImage, "ClassImage"); - getWidget(mClassName, "ClassName"); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); -} - -std::string GenerateClassResultDialog::getClassId() const -{ - return mClassName->getCaption(); -} - -void GenerateClassResultDialog::setClassId(const std::string &classId) -{ - mCurrentClassId = classId; - mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); - mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); -} - -// widget controls - -void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); -} - -void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -/* PickClassDialog */ - -PickClassDialog::PickClassDialog() - : WindowModal("openmw_chargen_class.layout") -{ - // Centre dialog - center(); - - getWidget(mSpecializationName, "SpecializationName"); - - getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); - getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); - - for(int i = 0; i < 5; i++) + GenerateClassResultDialog::GenerateClassResultDialog() + : WindowModal("openmw_chargen_generate_class_result.layout") { - char theIndex = '0'+i; - getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - } + // Centre dialog + center(); - getWidget(mClassList, "ClassList"); - mClassList->setScrollVisible(true); - mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); - mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + setText("ReflectT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sMessageQuestionAnswer1", "")); - getWidget(mClassImage, "ClassImage"); + getWidget(mClassImage, "ClassImage"); + getWidget(mClassName, "ClassName"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); - - updateClasses(); - updateStats(); -} - -void PickClassDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onOkClicked); + } -void PickClassDialog::open() -{ - WindowModal::open (); - updateClasses(); - updateStats(); -} - - -void PickClassDialog::setClassId(const std::string &classId) -{ - mCurrentClassId = classId; - mClassList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mClassList->getItemCount(); - for (size_t i = 0; i < count; ++i) + std::string GenerateClassResultDialog::getClassId() const { - if (boost::iequals(*mClassList->getItemDataAt(i), classId)) + return mClassName->getCaption(); + } + + void GenerateClassResultDialog::setClassId(const std::string &classId) + { + mCurrentClassId = classId; + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + mClassName->setCaption(MWBase::Environment::get().getWorld()->getStore().get().find(mCurrentClassId)->mName); + } + + // widget controls + + void GenerateClassResultDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); + } + + void GenerateClassResultDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + /* PickClassDialog */ + + PickClassDialog::PickClassDialog() + : WindowModal("openmw_chargen_class.layout") + { + // Centre dialog + center(); + + getWidget(mSpecializationName, "SpecializationName"); + + getWidget(mFavoriteAttribute[0], "FavoriteAttribute0"); + getWidget(mFavoriteAttribute[1], "FavoriteAttribute1"); + + for(int i = 0; i < 5; i++) { - mClassList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; + char theIndex = '0'+i; + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); } + + getWidget(mClassList, "ClassList"); + mClassList->setScrollVisible(true); + mClassList->eventListSelectAccept += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListMouseItemActivate += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + mClassList->eventListChangePosition += MyGUI::newDelegate(this, &PickClassDialog::onSelectClass); + + getWidget(mClassImage, "ClassImage"); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + + updateClasses(); + updateStats(); } - updateStats(); -} - -// widget controls - -void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - const std::string *classId = mClassList->getItemDataAt(_index); - if (boost::iequals(mCurrentClassId, *classId)) - return; - - mCurrentClassId = *classId; - updateStats(); -} - -// update widget content - -void PickClassDialog::updateClasses() -{ - mClassList->removeAllItems(); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - - int index = 0; - MWWorld::Store::iterator it = store.get().begin(); - for (; it != store.get().end(); ++it) + void PickClassDialog::setNextButtonShow(bool shown) { - bool playable = (it->mData.mIsPlayable != 0); - if (!playable) // Only display playable classes - continue; + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); - const std::string &id = it->mId; - mClassList->addItem(it->mName, id); - if (mCurrentClassId.empty()) + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void PickClassDialog::open() + { + WindowModal::open (); + updateClasses(); + updateStats(); + } + + + void PickClassDialog::setClassId(const std::string &classId) + { + mCurrentClassId = classId; + mClassList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mClassList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mCurrentClassId = id; - mClassList->setIndexSelected(index); + if (boost::iequals(*mClassList->getItemDataAt(i), classId)) + { + mClassList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } } - else if (boost::iequals(id, mCurrentClassId)) - { - mClassList->setIndexSelected(index); - } - ++index; - } -} -void PickClassDialog::updateStats() -{ - if (mCurrentClassId.empty()) - return; - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Class *klass = store.get().search(mCurrentClassId); - if (!klass) - return; - - ESM::Class::Specialization specialization = static_cast(klass->mData.mSpecialization); - - static const char *specIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" - }; - std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); - mSpecializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); - - mFavoriteAttribute[0]->setAttributeId(klass->mData.mAttribute[0]); - mFavoriteAttribute[1]->setAttributeId(klass->mData.mAttribute[1]); - ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); - ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); - - for (int i = 0; i < 5; ++i) - { - mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); - mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); - ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]); - ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]); + updateStats(); } - mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); -} + // widget controls -/* InfoBoxDialog */ - -void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) -{ - MyGUI::IntCoord inner = widget->getTextRegion(); - MyGUI::IntCoord outer = widget->getCoord(); - MyGUI::IntSize size = widget->getTextSize(); - size.width += outer.width - inner.width; - size.height += outer.height - inner.height; - widget->setSize(size); -} - -void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) -{ - size_t count = widget->getChildCount(); - int pos = 0; - pos += margin; - int width = 0; - for (unsigned i = 0; i < count; ++i) + void PickClassDialog::onOkClicked(MyGUI::Widget* _sender) { - MyGUI::Widget* child = widget->getChildAt(i); - if (!child->getVisible()) - continue; - - child->setPosition(child->getLeft(), pos); - width = std::max(width, child->getWidth()); - pos += child->getHeight() + margin; - } - width += margin*2; - widget->setSize(width, pos); -} - -InfoBoxDialog::InfoBoxDialog() - : WindowModal("openmw_infobox.layout") - , mCurrentButton(-1) -{ - getWidget(mTextBox, "TextBox"); - getWidget(mText, "Text"); - mText->getSubWidgetText()->setWordWrap(true); - getWidget(mButtonBar, "ButtonBar"); - - center(); -} - -void InfoBoxDialog::setText(const std::string &str) -{ - mText->setCaption(str); - mTextBox->setVisible(!str.empty()); - fitToText(mText); -} - -std::string InfoBoxDialog::getText() const -{ - return mText->getCaption(); -} - -void InfoBoxDialog::setButtons(ButtonList &buttons) -{ - for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - this->mButtons.clear(); - mCurrentButton = -1; - - // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget - MyGUI::Button* button; - MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); - ButtonList::const_iterator end = buttons.end(); - for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) - { - const std::string &text = *it; - button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); - button->getSubWidgetText()->setWordWrap(true); - button->setCaption(text); - fitToText(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); - coord.top += button->getHeight(); - this->mButtons.push_back(button); - } -} - -void InfoBoxDialog::open() -{ - WindowModal::open(); - // Fix layout - layoutVertically(mTextBox, 4); - layoutVertically(mButtonBar, 6); - layoutVertically(mMainWidget, 4 + 6); - - center(); -} - -int InfoBoxDialog::getChosenButton() const -{ - return mCurrentButton; -} - -void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) -{ - std::vector::const_iterator end = mButtons.end(); - int i = 0; - for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) - { - if (*it == _sender) - { - mCurrentButton = i; - eventButtonSelected(i); + if(mClassList->getIndexSelected() == MyGUI::ITEM_NONE) return; - } - ++i; - } -} - -/* ClassChoiceDialog */ - -ClassChoiceDialog::ClassChoiceDialog() - : InfoBoxDialog() -{ - setText(""); - ButtonList buttons; - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); - buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); - setButtons(buttons); -} - -/* CreateClassDialog */ - -CreateClassDialog::CreateClassDialog() - : WindowModal("openmw_chargen_create_class.layout") - , mSpecDialog(NULL) - , mAttribDialog(NULL) - , mSkillDialog(NULL) - , mDescDialog(NULL) -{ - // Centre dialog - center(); - - setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); - getWidget(mSpecializationName, "SpecializationName"); - mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); - - setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); - getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); - getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); - mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); - - setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); - setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); - for(int i = 0; i < 5; i++) - { - char theIndex = '0'+i; - getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); - getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); - mSkills.push_back(mMajorSkill[i]); - mSkills.push_back(mMinorSkill[i]); + eventDone(this); } - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + void PickClassDialog::onBackClicked(MyGUI::Widget* _sender) { - (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + eventBack(); } - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); - getWidget(mEditName, "EditName"); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); - - MyGUI::Button* descriptionButton; - getWidget(descriptionButton, "DescriptionButton"); - descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); - - // Set default skills, attributes - - mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); - mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); - - mMajorSkill[0]->setSkillId(ESM::Skill::Block); - mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); - mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); - mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); - mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); - - mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); - mMinorSkill[1]->setSkillId(ESM::Skill::Axe); - mMinorSkill[2]->setSkillId(ESM::Skill::Spear); - mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); - mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); - - setSpecialization(0); - update(); -} - -CreateClassDialog::~CreateClassDialog() -{ - delete mSpecDialog; - delete mAttribDialog; - delete mSkillDialog; - delete mDescDialog; -} - -void CreateClassDialog::update() -{ - for (int i = 0; i < 5; ++i) + void PickClassDialog::onSelectClass(MyGUI::ListBox* _sender, size_t _index) { - ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); - ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + const std::string *classId = mClassList->getItemDataAt(_index); + if (boost::iequals(mCurrentClassId, *classId)) + return; + + mCurrentClassId = *classId; + updateStats(); } - ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); - ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); -} + // update widget content -std::string CreateClassDialog::getName() const -{ - return mEditName->getOnlyText(); -} - -std::string CreateClassDialog::getDescription() const -{ - return mDescription; -} - -ESM::Class::Specialization CreateClassDialog::getSpecializationId() const -{ - return mSpecializationId; -} - -std::vector CreateClassDialog::getFavoriteAttributes() const -{ - std::vector v; - v.push_back(mFavoriteAttribute0->getAttributeId()); - v.push_back(mFavoriteAttribute1->getAttributeId()); - return v; -} - -std::vector CreateClassDialog::getMajorSkills() const -{ - std::vector v; - for(int i = 0; i < 5; i++) + void PickClassDialog::updateClasses() { - v.push_back(mMajorSkill[i]->getSkillId()); - } - return v; -} + mClassList->removeAllItems(); -std::vector CreateClassDialog::getMinorSkills() const -{ - std::vector v; - for(int i=0; i < 5; i++) - { - v.push_back(mMinorSkill[i]->getSkillId()); - } - return v; -} + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); -void CreateClassDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -// widget controls - -void CreateClassDialog::onDialogCancel() -{ - MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); - mSpecDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); - mAttribDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); - mSkillDialog = 0; - - MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); - mDescDialog = 0; -} - -void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) -{ - delete mSpecDialog; - mSpecDialog = new SelectSpecializationDialog(); - mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); - mSpecDialog->setVisible(true); -} - -void CreateClassDialog::onSpecializationSelected() -{ - mSpecializationId = mSpecDialog->getSpecializationId(); - setSpecialization(mSpecializationId); - - MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); - mSpecDialog = 0; -} - -void CreateClassDialog::setSpecialization(int id) -{ - mSpecializationId = (ESM::Class::Specialization) id; - static const char *specIds[3] = { - "sSpecializationCombat", - "sSpecializationMagic", - "sSpecializationStealth" - }; - std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); - mSpecializationName->setCaption(specName); - ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); -} - -void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) -{ - delete mAttribDialog; - mAttribDialog = new SelectAttributeDialog(); - mAffectedAttribute = _sender; - mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); - mAttribDialog->setVisible(true); -} - -void CreateClassDialog::onAttributeSelected() -{ - ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); - if (mAffectedAttribute == mFavoriteAttribute0) - { - if (mFavoriteAttribute1->getAttributeId() == id) - mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); - } - else if (mAffectedAttribute == mFavoriteAttribute1) - { - if (mFavoriteAttribute0->getAttributeId() == id) - mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); - } - mAffectedAttribute->setAttributeId(id); - MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); - mAttribDialog = 0; - - update(); -} - -void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) -{ - delete mSkillDialog; - mSkillDialog = new SelectSkillDialog(); - mAffectedSkill = _sender; - mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); - mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); - mSkillDialog->setVisible(true); -} - -void CreateClassDialog::onSkillSelected() -{ - ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); - - // Avoid duplicate skills by swapping any skill field that matches the selected one - std::vector::const_iterator end = mSkills.end(); - for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) - { - if (*it == mAffectedSkill) - continue; - if ((*it)->getSkillId() == id) + int index = 0; + MWWorld::Store::iterator it = store.get().begin(); + for (; it != store.get().end(); ++it) { - (*it)->setSkillId(mAffectedSkill->getSkillId()); - break; + bool playable = (it->mData.mIsPlayable != 0); + if (!playable) // Only display playable classes + continue; + + const std::string &id = it->mId; + mClassList->addItem(it->mName, id); + if (mCurrentClassId.empty()) + { + mCurrentClassId = id; + mClassList->setIndexSelected(index); + } + else if (boost::iequals(id, mCurrentClassId)) + { + mClassList->setIndexSelected(index); + } + ++index; } } - mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); - MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); - mSkillDialog = 0; - update(); -} + void PickClassDialog::updateStats() + { + if (mCurrentClassId.empty()) + return; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Class *klass = store.get().search(mCurrentClassId); + if (!klass) + return; -void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) -{ - mDescDialog = new DescriptionDialog(); - mDescDialog->setTextInput(mDescription); - mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); - mDescDialog->setVisible(true); -} + ESM::Class::Specialization specialization = static_cast(klass->mData.mSpecialization); -void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) -{ - mDescription = mDescDialog->getTextInput(); - MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); - mDescDialog = 0; -} + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[specialization], specIds[specialization]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, specialization); -void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(getName().size() <= 0) - return; - eventDone(this); -} + mFavoriteAttribute[0]->setAttributeId(klass->mData.mAttribute[0]); + mFavoriteAttribute[1]->setAttributeId(klass->mData.mAttribute[1]); + ToolTips::createAttributeToolTip(mFavoriteAttribute[0], mFavoriteAttribute[0]->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute[1], mFavoriteAttribute[1]->getAttributeId()); -void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} + for (int i = 0; i < 5; ++i) + { + mMinorSkill[i]->setSkillNumber(klass->mData.mSkills[i][0]); + mMajorSkill[i]->setSkillNumber(klass->mData.mSkills[i][1]); + ToolTips::createSkillToolTip(mMinorSkill[i], klass->mData.mSkills[i][0]); + ToolTips::createSkillToolTip(mMajorSkill[i], klass->mData.mSkills[i][1]); + } -/* SelectSpecializationDialog */ + mClassImage->setImageTexture(std::string("textures\\levelup\\") + mCurrentClassId + ".dds"); + } -SelectSpecializationDialog::SelectSpecializationDialog() - : WindowModal("openmw_chargen_select_specialization.layout") -{ - // Centre dialog - center(); + /* InfoBoxDialog */ - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); + void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) + { + MyGUI::IntCoord inner = widget->getTextRegion(); + MyGUI::IntCoord outer = widget->getCoord(); + MyGUI::IntSize size = widget->getTextSize(); + size.width += outer.width - inner.width; + size.height += outer.height - inner.height; + widget->setSize(size); + } - getWidget(mSpecialization0, "Specialization0"); - getWidget(mSpecialization1, "Specialization1"); - getWidget(mSpecialization2, "Specialization2"); - std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); - std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); - std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + void InfoBoxDialog::layoutVertically(MyGUI::Widget* widget, int margin) + { + size_t count = widget->getChildCount(); + int pos = 0; + pos += margin; + int width = 0; + for (unsigned i = 0; i < count; ++i) + { + MyGUI::Widget* child = widget->getChildAt(i); + if (!child->getVisible()) + continue; - mSpecialization0->setCaption(combat); - mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecialization1->setCaption(magic); - mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecialization2->setCaption(stealth); - mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); - mSpecializationId = ESM::Class::Combat; + child->setPosition(child->getLeft(), pos); + width = std::max(width, child->getWidth()); + pos += child->getHeight() + margin; + } + width += margin*2; + widget->setSize(width, pos); + } - ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); - ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); - ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); + InfoBoxDialog::InfoBoxDialog() + : WindowModal("openmw_infobox.layout") + , mCurrentButton(-1) + { + getWidget(mTextBox, "TextBox"); + getWidget(mText, "Text"); + mText->getSubWidgetText()->setWordWrap(true); + getWidget(mButtonBar, "ButtonBar"); - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); -} + center(); + } -SelectSpecializationDialog::~SelectSpecializationDialog() -{ -} + void InfoBoxDialog::setText(const std::string &str) + { + mText->setCaption(str); + mTextBox->setVisible(!str.empty()); + fitToText(mText); + } -// widget controls + std::string InfoBoxDialog::getText() const + { + return mText->getCaption(); + } -void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) -{ - if (_sender == mSpecialization0) + void InfoBoxDialog::setButtons(ButtonList &buttons) + { + for (std::vector::iterator it = this->mButtons.begin(); it != this->mButtons.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + this->mButtons.clear(); + mCurrentButton = -1; + + // TODO: The buttons should be generated from a template in the layout file, ie. cloning an existing widget + MyGUI::Button* button; + MyGUI::IntCoord coord = MyGUI::IntCoord(0, 0, mButtonBar->getWidth(), 10); + ButtonList::const_iterator end = buttons.end(); + for (ButtonList::const_iterator it = buttons.begin(); it != end; ++it) + { + const std::string &text = *it; + button = mButtonBar->createWidget("MW_Button", coord, MyGUI::Align::Top | MyGUI::Align::HCenter, ""); + button->getSubWidgetText()->setWordWrap(true); + button->setCaption(text); + fitToText(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &InfoBoxDialog::onButtonClicked); + coord.top += button->getHeight(); + this->mButtons.push_back(button); + } + } + + void InfoBoxDialog::open() + { + WindowModal::open(); + // Fix layout + layoutVertically(mTextBox, 4); + layoutVertically(mButtonBar, 6); + layoutVertically(mMainWidget, 4 + 6); + + center(); + } + + int InfoBoxDialog::getChosenButton() const + { + return mCurrentButton; + } + + void InfoBoxDialog::onButtonClicked(MyGUI::Widget* _sender) + { + std::vector::const_iterator end = mButtons.end(); + int i = 0; + for (std::vector::const_iterator it = mButtons.begin(); it != end; ++it) + { + if (*it == _sender) + { + mCurrentButton = i; + eventButtonSelected(i); + return; + } + ++i; + } + } + + /* ClassChoiceDialog */ + + ClassChoiceDialog::ClassChoiceDialog() + : InfoBoxDialog() + { + setText(""); + ButtonList buttons; + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu1", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu2", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sClassChoiceMenu3", "")); + buttons.push_back(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBack", "")); + setButtons(buttons); + } + + /* CreateClassDialog */ + + CreateClassDialog::CreateClassDialog() + : WindowModal("openmw_chargen_create_class.layout") + , mSpecDialog(NULL) + , mAttribDialog(NULL) + , mSkillDialog(NULL) + , mDescDialog(NULL) + { + // Centre dialog + center(); + + setText("SpecializationT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu1", "Specialization")); + getWidget(mSpecializationName, "SpecializationName"); + mSpecializationName->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationClicked); + + setText("FavoriteAttributesT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sChooseClassMenu2", "Favorite Attributes:")); + getWidget(mFavoriteAttribute0, "FavoriteAttribute0"); + getWidget(mFavoriteAttribute1, "FavoriteAttribute1"); + mFavoriteAttribute0->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + mFavoriteAttribute1->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeClicked); + + setText("MajorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMajor", "")); + setText("MinorSkillT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillClassMinor", "")); + for(int i = 0; i < 5; i++) + { + char theIndex = '0'+i; + getWidget(mMajorSkill[i], std::string("MajorSkill").append(1, theIndex)); + getWidget(mMinorSkill[i], std::string("MinorSkill").append(1, theIndex)); + mSkills.push_back(mMajorSkill[i]); + mSkills.push_back(mMinorSkill[i]); + } + + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + { + (*it)->eventClicked += MyGUI::newDelegate(this, &CreateClassDialog::onSkillClicked); + } + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sName", "")); + getWidget(mEditName, "EditName"); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); + + MyGUI::Button* descriptionButton; + getWidget(descriptionButton, "DescriptionButton"); + descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); + + // Set default skills, attributes + + mFavoriteAttribute0->setAttributeId(ESM::Attribute::Strength); + mFavoriteAttribute1->setAttributeId(ESM::Attribute::Agility); + + mMajorSkill[0]->setSkillId(ESM::Skill::Block); + mMajorSkill[1]->setSkillId(ESM::Skill::Armorer); + mMajorSkill[2]->setSkillId(ESM::Skill::MediumArmor); + mMajorSkill[3]->setSkillId(ESM::Skill::HeavyArmor); + mMajorSkill[4]->setSkillId(ESM::Skill::BluntWeapon); + + mMinorSkill[0]->setSkillId(ESM::Skill::LongBlade); + mMinorSkill[1]->setSkillId(ESM::Skill::Axe); + mMinorSkill[2]->setSkillId(ESM::Skill::Spear); + mMinorSkill[3]->setSkillId(ESM::Skill::Athletics); + mMinorSkill[4]->setSkillId(ESM::Skill::Enchant); + + setSpecialization(0); + update(); + } + + CreateClassDialog::~CreateClassDialog() + { + delete mSpecDialog; + delete mAttribDialog; + delete mSkillDialog; + delete mDescDialog; + } + + void CreateClassDialog::update() + { + for (int i = 0; i < 5; ++i) + { + ToolTips::createSkillToolTip(mMajorSkill[i], mMajorSkill[i]->getSkillId()); + ToolTips::createSkillToolTip(mMinorSkill[i], mMinorSkill[i]->getSkillId()); + } + + ToolTips::createAttributeToolTip(mFavoriteAttribute0, mFavoriteAttribute0->getAttributeId()); + ToolTips::createAttributeToolTip(mFavoriteAttribute1, mFavoriteAttribute1->getAttributeId()); + } + + std::string CreateClassDialog::getName() const + { + return mEditName->getOnlyText(); + } + + std::string CreateClassDialog::getDescription() const + { + return mDescription; + } + + ESM::Class::Specialization CreateClassDialog::getSpecializationId() const + { + return mSpecializationId; + } + + std::vector CreateClassDialog::getFavoriteAttributes() const + { + std::vector v; + v.push_back(mFavoriteAttribute0->getAttributeId()); + v.push_back(mFavoriteAttribute1->getAttributeId()); + return v; + } + + std::vector CreateClassDialog::getMajorSkills() const + { + std::vector v; + for(int i = 0; i < 5; i++) + { + v.push_back(mMajorSkill[i]->getSkillId()); + } + return v; + } + + std::vector CreateClassDialog::getMinorSkills() const + { + std::vector v; + for(int i=0; i < 5; i++) + { + v.push_back(mMinorSkill[i]->getSkillId()); + } + return v; + } + + void CreateClassDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + // widget controls + + void CreateClassDialog::onDialogCancel() + { + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); + mSpecDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); + mAttribDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); + mSkillDialog = 0; + + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); + mDescDialog = 0; + } + + void CreateClassDialog::onSpecializationClicked(MyGUI::Widget* _sender) + { + delete mSpecDialog; + mSpecDialog = new SelectSpecializationDialog(); + mSpecDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSpecDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSpecializationSelected); + mSpecDialog->setVisible(true); + } + + void CreateClassDialog::onSpecializationSelected() + { + mSpecializationId = mSpecDialog->getSpecializationId(); + setSpecialization(mSpecializationId); + + MWBase::Environment::get().getWindowManager()->removeDialog(mSpecDialog); + mSpecDialog = 0; + } + + void CreateClassDialog::setSpecialization(int id) + { + mSpecializationId = (ESM::Class::Specialization) id; + static const char *specIds[3] = { + "sSpecializationCombat", + "sSpecializationMagic", + "sSpecializationStealth" + }; + std::string specName = MWBase::Environment::get().getWindowManager()->getGameSettingString(specIds[mSpecializationId], specIds[mSpecializationId]); + mSpecializationName->setCaption(specName); + ToolTips::createSpecializationToolTip(mSpecializationName, specName, mSpecializationId); + } + + void CreateClassDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) + { + delete mAttribDialog; + mAttribDialog = new SelectAttributeDialog(); + mAffectedAttribute = _sender; + mAttribDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mAttribDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onAttributeSelected); + mAttribDialog->setVisible(true); + } + + void CreateClassDialog::onAttributeSelected() + { + ESM::Attribute::AttributeID id = mAttribDialog->getAttributeId(); + if (mAffectedAttribute == mFavoriteAttribute0) + { + if (mFavoriteAttribute1->getAttributeId() == id) + mFavoriteAttribute1->setAttributeId(mFavoriteAttribute0->getAttributeId()); + } + else if (mAffectedAttribute == mFavoriteAttribute1) + { + if (mFavoriteAttribute0->getAttributeId() == id) + mFavoriteAttribute0->setAttributeId(mFavoriteAttribute1->getAttributeId()); + } + mAffectedAttribute->setAttributeId(id); + MWBase::Environment::get().getWindowManager()->removeDialog(mAttribDialog); + mAttribDialog = 0; + + update(); + } + + void CreateClassDialog::onSkillClicked(Widgets::MWSkillPtr _sender) + { + delete mSkillDialog; + mSkillDialog = new SelectSkillDialog(); + mAffectedSkill = _sender; + mSkillDialog->eventCancel += MyGUI::newDelegate(this, &CreateClassDialog::onDialogCancel); + mSkillDialog->eventItemSelected += MyGUI::newDelegate(this, &CreateClassDialog::onSkillSelected); + mSkillDialog->setVisible(true); + } + + void CreateClassDialog::onSkillSelected() + { + ESM::Skill::SkillEnum id = mSkillDialog->getSkillId(); + + // Avoid duplicate skills by swapping any skill field that matches the selected one + std::vector::const_iterator end = mSkills.end(); + for (std::vector::const_iterator it = mSkills.begin(); it != end; ++it) + { + if (*it == mAffectedSkill) + continue; + if ((*it)->getSkillId() == id) + { + (*it)->setSkillId(mAffectedSkill->getSkillId()); + break; + } + } + + mAffectedSkill->setSkillId(mSkillDialog->getSkillId()); + MWBase::Environment::get().getWindowManager()->removeDialog(mSkillDialog); + mSkillDialog = 0; + update(); + } + + void CreateClassDialog::onDescriptionClicked(MyGUI::Widget* _sender) + { + mDescDialog = new DescriptionDialog(); + mDescDialog->setTextInput(mDescription); + mDescDialog->eventDone += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionEntered); + mDescDialog->setVisible(true); + } + + void CreateClassDialog::onDescriptionEntered(WindowBase* parWindow) + { + mDescription = mDescDialog->getTextInput(); + MWBase::Environment::get().getWindowManager()->removeDialog(mDescDialog); + mDescDialog = 0; + } + + void CreateClassDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(getName().size() <= 0) + return; + eventDone(this); + } + + void CreateClassDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + /* SelectSpecializationDialog */ + + SelectSpecializationDialog::SelectSpecializationDialog() + : WindowModal("openmw_chargen_select_specialization.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMenu1", "")); + + getWidget(mSpecialization0, "Specialization0"); + getWidget(mSpecialization1, "Specialization1"); + getWidget(mSpecialization2, "Specialization2"); + std::string combat = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Combat], ""); + std::string magic = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Magic], ""); + std::string stealth = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Class::sGmstSpecializationIds[ESM::Class::Stealth], ""); + + mSpecialization0->setCaption(combat); + mSpecialization0->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization1->setCaption(magic); + mSpecialization1->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); + mSpecialization2->setCaption(stealth); + mSpecialization2->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onSpecializationClicked); mSpecializationId = ESM::Class::Combat; - else if (_sender == mSpecialization1) - mSpecializationId = ESM::Class::Magic; - else if (_sender == mSpecialization2) - mSpecializationId = ESM::Class::Stealth; - else - return; - eventItemSelected(); -} + ToolTips::createSpecializationToolTip(mSpecialization0, combat, ESM::Class::Combat); + ToolTips::createSpecializationToolTip(mSpecialization1, magic, ESM::Class::Magic); + ToolTips::createSpecializationToolTip(mSpecialization2, stealth, ESM::Class::Stealth); -void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - -/* SelectAttributeDialog */ - -SelectAttributeDialog::SelectAttributeDialog() - : WindowModal("openmw_chargen_select_attribute.layout") -{ - // Centre dialog - center(); - - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); - - for (int i = 0; i < 8; ++i) - { - Widgets::MWAttributePtr attribute; - char theIndex = '0'+i; - - getWidget(attribute, std::string("Attribute").append(1, theIndex)); - attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); - attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); - ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSpecializationDialog::onCancelClicked); } - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); -} - -SelectAttributeDialog::~SelectAttributeDialog() -{ -} - -// widget controls - -void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) -{ - // TODO: Change MWAttribute to set and get AttributeID enum instead of int - mAttributeId = static_cast(_sender->getAttributeId()); - eventItemSelected(); -} - -void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - - -/* SelectSkillDialog */ - -SelectSkillDialog::SelectSkillDialog() - : WindowModal("openmw_chargen_select_skill.layout") -{ - // Centre dialog - center(); - - setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); - setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); - setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); - setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); - - for(int i = 0; i < 9; i++) + SelectSpecializationDialog::~SelectSpecializationDialog() { - char theIndex = '0'+i; - getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); - getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); - getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); } - struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { + // widget controls + + void SelectSpecializationDialog::onSpecializationClicked(MyGUI::Widget* _sender) + { + if (_sender == mSpecialization0) + mSpecializationId = ESM::Class::Combat; + else if (_sender == mSpecialization1) + mSpecializationId = ESM::Class::Magic; + else if (_sender == mSpecialization2) + mSpecializationId = ESM::Class::Stealth; + else + return; + + eventItemSelected(); + } + + void SelectSpecializationDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + /* SelectAttributeDialog */ + + SelectAttributeDialog::SelectAttributeDialog() + : WindowModal("openmw_chargen_select_attribute.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sAttributesMenu1", "")); + + for (int i = 0; i < 8; ++i) { - {mCombatSkill[0], ESM::Skill::Block}, - {mCombatSkill[1], ESM::Skill::Armorer}, - {mCombatSkill[2], ESM::Skill::MediumArmor}, - {mCombatSkill[3], ESM::Skill::HeavyArmor}, - {mCombatSkill[4], ESM::Skill::BluntWeapon}, - {mCombatSkill[5], ESM::Skill::LongBlade}, - {mCombatSkill[6], ESM::Skill::Axe}, - {mCombatSkill[7], ESM::Skill::Spear}, - {mCombatSkill[8], ESM::Skill::Athletics} - }, - { - {mMagicSkill[0], ESM::Skill::Enchant}, - {mMagicSkill[1], ESM::Skill::Destruction}, - {mMagicSkill[2], ESM::Skill::Alteration}, - {mMagicSkill[3], ESM::Skill::Illusion}, - {mMagicSkill[4], ESM::Skill::Conjuration}, - {mMagicSkill[5], ESM::Skill::Mysticism}, - {mMagicSkill[6], ESM::Skill::Restoration}, - {mMagicSkill[7], ESM::Skill::Alchemy}, - {mMagicSkill[8], ESM::Skill::Unarmored} - }, - { - {mStealthSkill[0], ESM::Skill::Security}, - {mStealthSkill[1], ESM::Skill::Sneak}, - {mStealthSkill[2], ESM::Skill::Acrobatics}, - {mStealthSkill[3], ESM::Skill::LightArmor}, - {mStealthSkill[4], ESM::Skill::ShortBlade}, - {mStealthSkill[5] ,ESM::Skill::Marksman}, - {mStealthSkill[6] ,ESM::Skill::Mercantile}, - {mStealthSkill[7] ,ESM::Skill::Speechcraft}, - {mStealthSkill[8] ,ESM::Skill::HandToHand} + Widgets::MWAttributePtr attribute; + char theIndex = '0'+i; + + getWidget(attribute, std::string("Attribute").append(1, theIndex)); + attribute->setAttributeId(ESM::Attribute::sAttributeIds[i]); + attribute->eventClicked += MyGUI::newDelegate(this, &SelectAttributeDialog::onAttributeClicked); + ToolTips::createAttributeToolTip(attribute, attribute->getAttributeId()); } - }; - for (int spec = 0; spec < 3; ++spec) - { - for (int i = 0; i < 9; ++i) - { - mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); - mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); - ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); - } + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectAttributeDialog::onCancelClicked); + } + + SelectAttributeDialog::~SelectAttributeDialog() + { + } + + // widget controls + + void SelectAttributeDialog::onAttributeClicked(Widgets::MWAttributePtr _sender) + { + // TODO: Change MWAttribute to set and get AttributeID enum instead of int + mAttributeId = static_cast(_sender->getAttributeId()); + eventItemSelected(); + } + + void SelectAttributeDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + + /* SelectSkillDialog */ + + SelectSkillDialog::SelectSkillDialog() + : WindowModal("openmw_chargen_select_skill.layout") + { + // Centre dialog + center(); + + setText("LabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSkillsMenu1", "")); + setText("CombatLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationCombat", "")); + setText("MagicLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationMagic", "")); + setText("StealthLabelT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sSpecializationStealth", "")); + + for(int i = 0; i < 9; i++) + { + char theIndex = '0'+i; + getWidget(mCombatSkill[i], std::string("CombatSkill").append(1, theIndex)); + getWidget(mMagicSkill[i], std::string("MagicSkill").append(1, theIndex)); + getWidget(mStealthSkill[i], std::string("StealthSkill").append(1, theIndex)); + } + + struct {Widgets::MWSkillPtr widget; ESM::Skill::SkillEnum skillId;} mSkills[3][9] = { + { + {mCombatSkill[0], ESM::Skill::Block}, + {mCombatSkill[1], ESM::Skill::Armorer}, + {mCombatSkill[2], ESM::Skill::MediumArmor}, + {mCombatSkill[3], ESM::Skill::HeavyArmor}, + {mCombatSkill[4], ESM::Skill::BluntWeapon}, + {mCombatSkill[5], ESM::Skill::LongBlade}, + {mCombatSkill[6], ESM::Skill::Axe}, + {mCombatSkill[7], ESM::Skill::Spear}, + {mCombatSkill[8], ESM::Skill::Athletics} + }, + { + {mMagicSkill[0], ESM::Skill::Enchant}, + {mMagicSkill[1], ESM::Skill::Destruction}, + {mMagicSkill[2], ESM::Skill::Alteration}, + {mMagicSkill[3], ESM::Skill::Illusion}, + {mMagicSkill[4], ESM::Skill::Conjuration}, + {mMagicSkill[5], ESM::Skill::Mysticism}, + {mMagicSkill[6], ESM::Skill::Restoration}, + {mMagicSkill[7], ESM::Skill::Alchemy}, + {mMagicSkill[8], ESM::Skill::Unarmored} + }, + { + {mStealthSkill[0], ESM::Skill::Security}, + {mStealthSkill[1], ESM::Skill::Sneak}, + {mStealthSkill[2], ESM::Skill::Acrobatics}, + {mStealthSkill[3], ESM::Skill::LightArmor}, + {mStealthSkill[4], ESM::Skill::ShortBlade}, + {mStealthSkill[5] ,ESM::Skill::Marksman}, + {mStealthSkill[6] ,ESM::Skill::Mercantile}, + {mStealthSkill[7] ,ESM::Skill::Speechcraft}, + {mStealthSkill[8] ,ESM::Skill::HandToHand} + } + }; + + for (int spec = 0; spec < 3; ++spec) + { + for (int i = 0; i < 9; ++i) + { + mSkills[spec][i].widget->setSkillId(mSkills[spec][i].skillId); + mSkills[spec][i].widget->eventClicked += MyGUI::newDelegate(this, &SelectSkillDialog::onSkillClicked); + ToolTips::createSkillToolTip(mSkills[spec][i].widget, mSkills[spec][i].widget->getSkillId()); + } + } + + MyGUI::Button* cancelButton; + getWidget(cancelButton, "CancelButton"); + cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); + cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); + } + + SelectSkillDialog::~SelectSkillDialog() + { + } + + // widget controls + + void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) + { + mSkillId = _sender->getSkillId(); + eventItemSelected(); + } + + void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) + { + eventCancel(); + } + + /* DescriptionDialog */ + + DescriptionDialog::DescriptionDialog() + : WindowModal("openmw_chargen_class_description.layout") + { + // Centre dialog + center(); + + getWidget(mTextEdit, "TextEdit"); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + } + + DescriptionDialog::~DescriptionDialog() + { + } + + // widget controls + + void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); } - MyGUI::Button* cancelButton; - getWidget(cancelButton, "CancelButton"); - cancelButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sCancel", "")); - cancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SelectSkillDialog::onCancelClicked); -} - -SelectSkillDialog::~SelectSkillDialog() -{ -} - -// widget controls - -void SelectSkillDialog::onSkillClicked(Widgets::MWSkillPtr _sender) -{ - mSkillId = _sender->getSkillId(); - eventItemSelected(); -} - -void SelectSkillDialog::onCancelClicked(MyGUI::Widget* _sender) -{ - eventCancel(); -} - -/* DescriptionDialog */ - -DescriptionDialog::DescriptionDialog() - : WindowModal("openmw_chargen_class_description.layout") -{ - // Centre dialog - center(); - - getWidget(mTextEdit, "TextEdit"); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DescriptionDialog::onOkClicked); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -DescriptionDialog::~DescriptionDialog() -{ -} - -// widget controls - -void DescriptionDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); } diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index bd1b0fe7ab..463c645dc2 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -278,16 +278,15 @@ namespace MWGui std::string Console::complete( std::string input, std::vector &matches ) { - using namespace std; - string output=input; - string tmp=input; + std::string output = input; + std::string tmp = input; bool has_front_quote = false; /* Does the input string contain things that don't have to be completed? If yes erase them. */ /* Are there quotation marks? */ - if( tmp.find('"') != string::npos ) { + if( tmp.find('"') != std::string::npos ) { int numquotes=0; - for(string::iterator it=tmp.begin(); it < tmp.end(); ++it) { + for(std::string::iterator it=tmp.begin(); it < tmp.end(); ++it) { if( *it == '"' ) numquotes++; } @@ -299,7 +298,7 @@ namespace MWGui } else { size_t pos; - if( ( ((pos = tmp.rfind(' ')) != string::npos ) ) && ( pos > tmp.rfind('"') ) ) { + if( ( ((pos = tmp.rfind(' ')) != std::string::npos ) ) && ( pos > tmp.rfind('"') ) ) { tmp.erase( 0, tmp.rfind(' ')+1); } else { @@ -311,7 +310,7 @@ namespace MWGui /* No quotation marks. Are there spaces?*/ else { size_t rpos; - if( (rpos=tmp.rfind(' ')) != string::npos ) { + if( (rpos=tmp.rfind(' ')) != std::string::npos ) { if( rpos == 0 ) { tmp.clear(); } @@ -330,7 +329,7 @@ namespace MWGui } /* Iterate through the vector. */ - for(vector::iterator it=mNames.begin(); it < mNames.end();++it) { + for(std::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. */ @@ -338,7 +337,7 @@ namespace MWGui continue; /* Is the beginning of the string different from the input string? If yes skip it. */ - for( string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { + for( std::string::iterator iter=tmp.begin(), iter2=(*it).begin(); iter < tmp.end();iter++, iter2++) { if( tolower(*iter) != tolower(*iter2) ) { string_different=true; break; @@ -361,24 +360,24 @@ namespace MWGui /* Only one match. We're done. */ if( matches.size() == 1 ) { /* Adding quotation marks when the input string started with a quotation mark or has spaces in it*/ - if( ( matches.front().find(' ') != string::npos ) ) { + if( ( matches.front().find(' ') != std::string::npos ) ) { if( !has_front_quote ) - output.append(string("\"")); - return output.append(matches.front() + string("\" ")); + output.append(std::string("\"")); + return output.append(matches.front() + std::string("\" ")); } else if( has_front_quote ) { - return output.append(matches.front() + string("\" ")); + return output.append(matches.front() + std::string("\" ")); } else { - return output.append(matches.front() + string(" ")); + return output.append(matches.front() + std::string(" ")); } } /* Check if all matching strings match further than input. If yes complete to this match. */ 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(std::string::iterator iter=matches.front().begin()+tmp.length(); iter < matches.front().end(); iter++, i++) { + for(std::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 d15a5acd3e..16f2535310 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -14,10 +14,6 @@ #include "tradewindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; -using namespace Widgets; - - namespace { bool compareType(std::string type1, std::string type2) @@ -68,686 +64,690 @@ namespace } } - -ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) - : mDragAndDrop(dragAndDrop) - , mFilter(ContainerBase::Filter_All) - , mDisplayEquippedItems(true) - , mHighlightEquippedItems(true) +namespace MWGui { -} -void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView) -{ - mContainerWidget = containerWidget; - mItemView = itemView; - - mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); - mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); -} - -ContainerBase::~ContainerBase() -{ -} - -void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) -{ - mSelectedItem = _sender; - - if (mDragAndDrop && !isTrading()) + ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) + : mDragAndDrop(dragAndDrop) + , mFilter(ContainerBase::Filter_All) + , mDisplayEquippedItems(true) + , mHighlightEquippedItems(true) { - if(!mDragAndDrop->mIsOnDragAndDrop) + } + + void ContainerBase::setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView) + { + mContainerWidget = containerWidget; + mItemView = itemView; + + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); + mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); + } + + ContainerBase::~ContainerBase() + { + } + + void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) + { + mSelectedItem = _sender; + + if (mDragAndDrop && !isTrading()) + { + if(!mDragAndDrop->mIsOnDragAndDrop) + { + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + startDragItem(_sender, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + startDragItem(_sender, 1); + } + else + { + std::string message = "#{sTake}"; + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); + } + } + else + onContainerClicked(mContainerWidget); + } + else if (isTrading()) { MWWorld::Ptr object = (*_sender->getUserData()); int count = object.getRefData().getCount(); - if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + if (isInventory()) { - startDragItem(_sender, count); - } - else if (MyGUI::InputManager::getInstance().isControlPressed()) - { - startDragItem(_sender, 1); - } - else - { - std::string message = "#{sTake}"; - CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); - dialog->open(MWWorld::Class::get(object).getName(object), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); - } - } - else - onContainerClicked(mContainerWidget); - } - else if (isTrading()) - { - 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("#{sBarterDialog4}"); - return; - } - } - - bool buying = isTradeWindow(); // buying or selling? - std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}"; - - 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), message, 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), message, count); - dialog->eventOkClicked.clear(); - dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); - } - } - } - else - { - onSelectedItemImpl(*_sender->getUserData()); - } -} - -void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) -{ - MWWorld::Ptr object = *mSelectedItem->getUserData(); - - if (isInventory()) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); - } - else - { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); - 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(); -} - -void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) -{ - MWWorld::Ptr object = *mSelectedItem->getUserData(); - - if (isInventory()) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); - } - else - { - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); - 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(); -} - -void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) -{ - mDragAndDrop->mIsOnDragAndDrop = true; - mSelectedItem->detachFromWidget(); - mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); - - MWWorld::Ptr object = *mSelectedItem->getUserData(); - _unequipItem(object); - - 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); - - 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->mDraggedCount)); - - drawItems(); - - MWBase::Environment::get().getWindowManager()->setDragDrop(true); -} - -void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) -{ - if (mDragAndDrop == NULL) return; - - if(mDragAndDrop->mIsOnDragAndDrop) //drop item here - { - MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - 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 (mPtr.getTypeName() == typeid(ESM::Container).name()) - { - MWWorld::LiveCellRef* ref = mPtr.get(); - if (ref->mBase->mFlags & ESM::Container::Organic) + // the player is trying to sell an item, check if the merchant accepts it + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object)) { - // user notification + // user notification "i don't buy this item" MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage2}"); - + messageBox("#{sBarterDialog4}"); return; } } - int origCount = object.getRefData().getCount(); + bool buying = isTradeWindow(); // buying or selling? + std::string message = buying ? "#{sQuanityMenuMessage02}" : "#{sQuanityMenuMessage01}"; - // check that we don't exceed the allowed weight (only for containers, not for inventory) - if (!isInventory()) + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) { - 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(mPtr).getEncumbrance(mPtr); - if (curWeight > capacity) + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) { - it->getRefData().setCount(0); - object.getRefData().setCount(origCount); - // user notification - MWBase::Environment::get().getWindowManager()-> - messageBox("#{sContentsMessage3}"); - - return; + sellAlreadyBoughtItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellAlreadyBoughtItem(NULL, 1); } else { - object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); } } else { - object.getRefData().setCount (mDragAndDrop->mDraggedCount); - containerStore.add(object); - object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + 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), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); + } } } + else + { + onSelectedItemImpl(*_sender->getUserData()); + } + } - mDragAndDrop->mIsOnDragAndDrop = false; - MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - drawItems(); - mDragAndDrop->mDraggedFrom->drawItems(); + void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) + { + MWWorld::Ptr object = *mSelectedItem->getUserData(); - mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); - notifyItemDragged(object, mDragAndDrop->mDraggedCount); + if (isInventory()) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, true); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, true); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - } -} -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(int filter) -{ - mFilter = filter; - drawItems(); -} - -void ContainerBase::openContainer(MWWorld::Ptr container) -{ - mPtr = container; -} - -void ContainerBase::drawItems() -{ - while (mContainerWidget->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); - } - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - int x = 0; - int y = 0; - int maxHeight = mItemView->getSize().height - 58; - - bool onlyMagic = false; - bool noMagic = false; - int categories = 0; - if (mFilter & Filter_All) - categories |= MWWorld::ContainerStore::Type_All; - if (mFilter & Filter_Weapon) - categories |= MWWorld::ContainerStore::Type_Weapon; - if (mFilter & Filter_Apparel) - categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; - 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; - } - if (mFilter & Filter_Misc) - { - 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_Probe; - } - if (mFilter & Filter_Ingredients) - categories |= MWWorld::ContainerStore::Type_Ingredient; - if (mFilter & Filter_ChargedSoulstones) - categories |= MWWorld::ContainerStore::Type_Miscellaneous; - if (mFilter & Filter_NoMagic) - noMagic = true; - - /// \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(); - - // 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) ); + drawItems(); } - // 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) + void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) { - std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); - if (found != unwantedItems.end()) + MWWorld::Ptr object = *mSelectedItem->getUserData(); + + if (isInventory()) { - unwantedItems.erase(found); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count, false); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); } - } - // now erase everything that's still in unwantedItems. - for (std::vector::iterator it=unwantedItems.begin(); - it != unwantedItems.end(); ++it) - { - 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) - if (mDisplayEquippedItems && mHighlightEquippedItems) - { - for (std::vector::const_iterator it=equippedItems.begin(); - it != equippedItems.end(); ++it) + else { - items.push_back( std::make_pair(*it, ItemState_Equipped) ); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count, false); + 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(); } - std::vector ignoreItems = itemsToIgnore(); - - // now add the regular items - std::vector regularItems; - for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) { - if ( (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() - || (!mHighlightEquippedItems && mDisplayEquippedItems)) - && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() - && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) - regularItems.push_back(*iter); + mDragAndDrop->mIsOnDragAndDrop = true; + mSelectedItem->detachFromWidget(); + mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); + + MWWorld::Ptr object = *mSelectedItem->getUserData(); + _unequipItem(object); + + 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); + + 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->mDraggedCount)); + + drawItems(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); } - // sort them and add - std::sort(regularItems.begin(), regularItems.end(), sortItems); - for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) { - items.push_back( std::make_pair(*it, ItemState_Normal) ); - } + if (mDragAndDrop == NULL) return; - for (std::vector< std::pair >::const_iterator it=items.begin(); - it != items.end(); ++it) - { - const MWWorld::Ptr* iter = &((*it).first); - - - if (onlyMagic - && it->second != ItemState_Barter - && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" - && iter->getTypeName() != typeid(ESM::Potion).name()) - continue; - - if (noMagic - && it->second != ItemState_Barter - && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" - || iter->getTypeName() == typeid(ESM::Potion).name())) - continue; - - if ( (mFilter & Filter_ChargedSoulstones) - && !isChargedSoulstone(*iter)) - continue; - - int displayCount = iter->getRefData().getCount(); - if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + if(mDragAndDrop->mIsOnDragAndDrop) //drop item here { - displayCount -= mDragAndDrop->mDraggedCount; - } - if(displayCount > 0) - { - std::string path = std::string("icons\\"); - path += MWWorld::Class::get(*iter).getInventoryIcon(*iter); + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - // background widget (for the "equipped" frame and magic item background image) - bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); - MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); - backgroundWidget->setUserString("ToolTipType", "ItemPtr"); - backgroundWidget->setUserData(*iter); - - std::string backgroundTex = "textures\\menu_icon"; - if (isMagic) - backgroundTex += "_magic"; - if (it->second == ItemState_Normal) + if (mDragAndDrop->mDraggedFrom != this) { - if (!isMagic) - backgroundTex = ""; - } - else if (it->second == ItemState_Equipped) - { - backgroundTex += "_equip"; - } - else if (it->second == ItemState_Barter) - { - backgroundTex += "_barter"; - } - if (backgroundTex != "") - backgroundTex += ".dds"; + assert(object.getContainerStore() && "Item is not in a container!"); - backgroundWidget->setImageTexture(backgroundTex); - 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); + // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside + if (mPtr.getTypeName() == typeid(ESM::Container).name()) + { + MWWorld::LiveCellRef* ref = mPtr.get(); + if (ref->mBase->mFlags & ESM::Container::Organic) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage2}"); - // image - MyGUI::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); + return; + } + } - // 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(displayCount)); + int origCount = object.getRefData().getCount(); - y += 42; - if (y > maxHeight) - { - x += 42; - y = 0; + // check that we don't exceed the allowed weight (only for containers, not for inventory) + if (!isInventory()) + { + 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(mPtr).getEncumbrance(mPtr); + if (curWeight > capacity) + { + it->getRefData().setCount(0); + object.getRefData().setCount(origCount); + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox("#{sContentsMessage3}"); + + return; + } + else + { + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + } + } + else + { + object.getRefData().setCount (mDragAndDrop->mDraggedCount); + containerStore.add(object); + object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + } } + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); + + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + notifyItemDragged(object, mDragAndDrop->mDraggedCount); + + 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); } } - 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) -{ - if (count == 1) - return ""; - if (count > 9999) - return boost::lexical_cast(int(count/1000.f)) + "k"; - else - return boost::lexical_cast(count); -} - -void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) -{ - int origCount = item.getRefData().getCount(); - item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); - item.getRefData().setCount(origCount - count); -} - -void ContainerBase::addItem(MWWorld::Ptr item, int count) -{ - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - int origCount = item.getRefData().getCount(); - - item.getRefData().setCount(count); - MWWorld::ContainerStoreIterator it = containerStore.add(item); - - item.getRefData().setCount(origCount - count); -} - -void ContainerBase::transferBoughtItems() -{ - MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - - for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) { - containerStore.add(*it); + 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::returnBoughtItems(MWWorld::ContainerStore& store) -{ - for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + void ContainerBase::setFilter(int filter) { - store.add(*it); + mFilter = filter; + drawItems(); } -} -std::vector ContainerBase::getEquippedItems() -{ - if (mPtr.getTypeName() != typeid(ESM::NPC).name()) - return std::vector(); - - MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); - - std::vector items; - - for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + void ContainerBase::openContainer(MWWorld::Ptr container) { - MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); - if (it != invStore.end()) + mPtr = container; + } + + void ContainerBase::drawItems() + { + while (mContainerWidget->getChildCount()) { - items.push_back(*it); + MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); } - } - - return items; -} - -MWWorld::ContainerStore& ContainerBase::getContainerStore() -{ - MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); - return store; -} - -// ------------------------------------------------------------------------------------------------ - -ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) - : ContainerBase(dragAndDrop) - , WindowBase("openmw_container_window.layout") -{ - getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); - getWidget(mTakeButton, "TakeButton"); - getWidget(mCloseButton, "CloseButton"); - - MyGUI::ScrollView* itemView; - MyGUI::Widget* containerWidget; - getWidget(containerWidget, "Items"); - getWidget(itemView, "ItemView"); - setWidgets(containerWidget, itemView); - - mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); - - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); - - setCoord(200,0,600,300); -} - -ContainerWindow::~ContainerWindow() -{ -} - -void ContainerWindow::onWindowResize(MyGUI::Window* window) -{ - drawItems(); -} - -void ContainerWindow::open(MWWorld::Ptr container, bool loot) -{ - mDisplayEquippedItems = true; - mHighlightEquippedItems = false; - if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) - { - // we are stealing stuff - mDisplayEquippedItems = false; - } - - mDisposeCorpseButton->setVisible(loot); - - openContainer(container); - setTitle(MWWorld::Class::get(container).getName(container)); - drawItems(); -} - -void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); - } -} - -void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - // transfer everything into the player's inventory MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + int x = 0; + int y = 0; + int maxHeight = mItemView->getSize().height - 58; + + bool onlyMagic = false; + bool noMagic = false; + int categories = 0; + if (mFilter & Filter_All) + categories |= MWWorld::ContainerStore::Type_All; + if (mFilter & Filter_Weapon) + categories |= MWWorld::ContainerStore::Type_Weapon; + if (mFilter & Filter_Apparel) + categories |= MWWorld::ContainerStore::Type_Clothing | MWWorld::ContainerStore::Type_Armor; + 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; + } + if (mFilter & Filter_Misc) + { + 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_Probe; + } + if (mFilter & Filter_Ingredients) + categories |= MWWorld::ContainerStore::Type_Ingredient; + if (mFilter & Filter_ChargedSoulstones) + categories |= MWWorld::ContainerStore::Type_Miscellaneous; + if (mFilter & Filter_NoMagic) + noMagic = true; + + /// \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(); - 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) + // add bought items (always at the beginning) + std::vector boughtItems; + for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) { - if (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() - && !mDisplayEquippedItems) - continue; + boughtItems.push_back(*it); + } + std::sort(boughtItems.begin(), boughtItems.end(), sortItems); - 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); - } - - iter->getRefData().setCount(0); - - ++i; + for (std::vector::iterator it=boughtItems.begin(); + it != boughtItems.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) + { + 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) + { + 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) + if (mDisplayEquippedItems && mHighlightEquippedItems) + { + for (std::vector::const_iterator it=equippedItems.begin(); + it != equippedItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Equipped) ); + } + } + + 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() + || (!mHighlightEquippedItems && mDisplayEquippedItems)) + && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() + && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) + 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(); + it != items.end(); ++it) + { + const MWWorld::Ptr* iter = &((*it).first); + + + if (onlyMagic + && it->second != ItemState_Barter + && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" + && iter->getTypeName() != typeid(ESM::Potion).name()) + continue; + + if (noMagic + && it->second != ItemState_Barter + && (MWWorld::Class::get(*iter).getEnchantment(*iter) != "" + || iter->getTypeName() == typeid(ESM::Potion).name())) + continue; + + if ( (mFilter & Filter_ChargedSoulstones) + && !isChargedSoulstone(*iter)) + continue; + + int displayCount = iter->getRefData().getCount(); + if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + { + displayCount -= mDragAndDrop->mDraggedCount; + } + if(displayCount > 0) + { + std::string path = std::string("icons\\"); + 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) != ""); + MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); + backgroundWidget->setUserString("ToolTipType", "ItemPtr"); + backgroundWidget->setUserData(*iter); + + 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"; + } + else if (it->second == ItemState_Barter) + { + backgroundTex += "_barter"; + } + if (backgroundTex != "") + backgroundTex += ".dds"; + + backgroundWidget->setImageTexture(backgroundTex); + 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); + + // image + MyGUI::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(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(displayCount)); + + y += 42; + if (y > maxHeight) + { + x += 42; + y = 0; + } + + } + } + + 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) + { + if (count == 1) + return ""; + if (count > 9999) + return boost::lexical_cast(int(count/1000.f)) + "k"; + else + return boost::lexical_cast(count); + } + + void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) + { + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); + item.getRefData().setCount(origCount - count); + } + + void ContainerBase::addItem(MWWorld::Ptr item, int count) + { + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + int origCount = item.getRefData().getCount(); + + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = containerStore.add(item); + + item.getRefData().setCount(origCount - count); + } + + void ContainerBase::transferBoughtItems() + { + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + containerStore.add(*it); + } + } + + void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) + { + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + store.add(*it); + } + } + + std::vector ContainerBase::getEquippedItems() + { + if (mPtr.getTypeName() != typeid(ESM::NPC).name()) + return std::vector(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mPtr).getInventoryStore(mPtr); + + 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; + } + + MWWorld::ContainerStore& ContainerBase::getContainerStore() + { + MWWorld::ContainerStore& store = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + return store; + } + + // ------------------------------------------------------------------------------------------------ + + ContainerWindow::ContainerWindow(DragAndDrop* dragAndDrop) + : ContainerBase(dragAndDrop) + , WindowBase("openmw_container_window.layout") + { + getWidget(mDisposeCorpseButton, "DisposeCorpseButton"); + getWidget(mTakeButton, "TakeButton"); + getWidget(mCloseButton, "CloseButton"); + + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + mDisposeCorpseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onDisposeCorpseButtonClicked); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); + + setCoord(200,0,600,300); + } + + ContainerWindow::~ContainerWindow() + { + } + + void ContainerWindow::onWindowResize(MyGUI::Window* window) + { + drawItems(); + } + + void ContainerWindow::open(MWWorld::Ptr container, bool loot) + { + mDisplayEquippedItems = true; + mHighlightEquippedItems = false; + if (container.getTypeName() == typeid(ESM::NPC).name() && !loot) + { + // we are stealing stuff + mDisplayEquippedItems = false; + } + + mDisposeCorpseButton->setVisible(loot); + + openContainer(container); + setTitle(MWWorld::Class::get(container).getName(container)); + drawItems(); + } + + void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } + } + + void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + // transfer everything into the player's inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mPtr).getContainerStore(mPtr); + + std::vector equippedItems = getEquippedItems(); + + 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 (std::find(equippedItems.begin(), equippedItems.end(), *iter) != equippedItems.end() + && !mDisplayEquippedItems) + continue; + + 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); + } + + iter->getRefData().setCount(0); + + ++i; + } + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } + } + + void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) + { + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + onTakeAllButtonClicked(mTakeButton); + + /// \todo I don't think this is the correct flag to check + if (MWWorld::Class::get(mPtr).isEssential(mPtr)) + MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); + else + MWBase::Environment::get().getWorld()->deleteObject(mPtr); + + mPtr = MWWorld::Ptr(); + } + } + + void ContainerWindow::onReferenceUnavailable() + { MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); } -} - -void ContainerWindow::onDisposeCorpseButtonClicked(MyGUI::Widget *sender) -{ - if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) - { - onTakeAllButtonClicked(mTakeButton); - - /// \todo I don't think this is the correct flag to check - if (MWWorld::Class::get(mPtr).isEssential(mPtr)) - MWBase::Environment::get().getWindowManager()->messageBox("#{sDisposeCorpseFail}"); - else - MWBase::Environment::get().getWorld()->deleteObject(mPtr); - - mPtr = MWWorld::Ptr(); - } -} - -void ContainerWindow::onReferenceUnavailable() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Container); + } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 392f641264..b596cef018 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -19,521 +19,521 @@ #include "inventorywindow.hpp" #include "travelwindow.hpp" -using namespace MWGui; -using namespace Widgets; - /** *Copied from the internet. */ -namespace { - -std::string lower_string(const std::string& str) +namespace { - std::string lowerCase = Misc::StringUtils::lowerCase (str); - return lowerCase; -} - -std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) -{ - return lower_string(str).find(lower_string(substr),pos); -} - -bool sortByLength (const std::string& left, const std::string& right) -{ - return left.size() > right.size(); -} -} - - - -PersuasionDialog::PersuasionDialog() - : WindowModal("openmw_persuasion_dialog.layout") -{ - getWidget(mCancelButton, "CancelButton"); - getWidget(mAdmireButton, "AdmireButton"); - getWidget(mIntimidateButton, "IntimidateButton"); - getWidget(mTauntButton, "TauntButton"); - getWidget(mBribe10Button, "Bribe10Button"); - getWidget(mBribe100Button, "Bribe100Button"); - getWidget(mBribe1000Button, "Bribe1000Button"); - getWidget(mGoldLabel, "GoldLabel"); - - mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); - mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); - mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); -} - -void PersuasionDialog::onCancel(MyGUI::Widget *sender) -{ - setVisible(false); -} - -void PersuasionDialog::onPersuade(MyGUI::Widget *sender) -{ - MWBase::MechanicsManager::PersuasionType type; - if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; - else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; - else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; - else if (sender == mBribe10Button) + std::string lower_string(const std::string& str) { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); - type = MWBase::MechanicsManager::PT_Bribe10; - } - else if (sender == mBribe100Button) - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); - type = MWBase::MechanicsManager::PT_Bribe100; - } - else /*if (sender == mBribe1000Button)*/ - { - MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); - type = MWBase::MechanicsManager::PT_Bribe1000; + std::string lowerCase = Misc::StringUtils::lowerCase (str); + + return lowerCase; } - MWBase::Environment::get().getDialogueManager()->persuade(type); - - setVisible(false); -} - -void PersuasionDialog::open() -{ - WindowModal::open(); - center(); - - int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); - - mBribe10Button->setEnabled (playerGold >= 10); - mBribe100Button->setEnabled (playerGold >= 100); - mBribe1000Button->setEnabled (playerGold >= 1000); - - mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); -} - -// -------------------------------------------------------------------------------------------------- - -DialogueWindow::DialogueWindow() - : WindowBase("openmw_dialogue_window.layout") - , mPersuasionDialog() - , mEnabled(false) - , mServices(0) -{ - // Centre dialog - center(); - - mPersuasionDialog.setVisible(false); - - //History view - getWidget(mHistory, "History"); - mHistory->setOverflowToTheLeft(true); - mHistory->setMaxTextLength(1000000); - MyGUI::Widget* eventbox; - - //An EditBox cannot receive mouse click events, so we use an - //invisible widget on top of the editbox to receive them - getWidget(eventbox, "EventBox"); - eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); - eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); - - //Topics list - getWidget(mTopicsList, "TopicsList"); - mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - - MyGUI::Button* byeButton; - getWidget(byeButton, "ByeButton"); - byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - - getWidget(mDispositionBar, "Disposition"); - getWidget(mDispositionText,"DispositionText"); - - static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); -} - -void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) -{ - MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); - if(t == NULL) - return; - - const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); - - size_t cursorPosition = t->getCursorPosition(lastPressed); - MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); - - if (!mEnabled && color == "#572D21") - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); - - if (!mEnabled) - return; - - if(color != "#B29154") + std::string::size_type find_str_ci(const std::string& str, const std::string& substr,size_t pos) { - MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); + return lower_string(str).find(lower_string(substr),pos); + } - if(color == "#686EBA") + bool sortByLength (const std::string& left, const std::string& right) + { + return left.size() > right.size(); + } +} + +namespace MWGui +{ + + PersuasionDialog::PersuasionDialog() + : WindowModal("openmw_persuasion_dialog.layout") + { + getWidget(mCancelButton, "CancelButton"); + getWidget(mAdmireButton, "AdmireButton"); + getWidget(mIntimidateButton, "IntimidateButton"); + getWidget(mTauntButton, "TauntButton"); + getWidget(mBribe10Button, "Bribe10Button"); + getWidget(mBribe100Button, "Bribe100Button"); + getWidget(mBribe1000Button, "Bribe1000Button"); + getWidget(mGoldLabel, "GoldLabel"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onCancel); + mAdmireButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mIntimidateButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mTauntButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe10Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe100Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + mBribe1000Button->eventMouseButtonClick += MyGUI::newDelegate(this, &PersuasionDialog::onPersuade); + } + + void PersuasionDialog::onCancel(MyGUI::Widget *sender) + { + setVisible(false); + } + + void PersuasionDialog::onPersuade(MyGUI::Widget *sender) + { + MWBase::MechanicsManager::PersuasionType type; + if (sender == mAdmireButton) type = MWBase::MechanicsManager::PT_Admire; + else if (sender == mIntimidateButton) type = MWBase::MechanicsManager::PT_Intimidate; + else if (sender == mTauntButton) type = MWBase::MechanicsManager::PT_Taunt; + else if (sender == mBribe10Button) { - std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); - if( !mHyperLinks.empty() ) - { - --i; - - if( i->first + i->second.mLength > cursorPosition) - { - MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); - } - } - else - { - // the link was colored, but it is not in mHyperLinks. - // It means that those liunks are not marked with @# and found - // by topic name search - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); - } + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-10); + type = MWBase::MechanicsManager::PT_Bribe10; + } + else if (sender == mBribe100Button) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-100); + type = MWBase::MechanicsManager::PT_Bribe100; + } + else /*if (sender == mBribe1000Button)*/ + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addOrRemoveGold(-1000); + type = MWBase::MechanicsManager::PT_Bribe1000; } - if(color == "#572D21") - MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); - } -} + MWBase::Environment::get().getDialogueManager()->persuade(type); -void DialogueWindow::onWindowResize(MyGUI::Window* _sender) -{ - mTopicsList->adjustSize(); -} - -void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mHistory->getVScrollPosition() - _rel*0.3 < 0) - mHistory->setVScrollPosition(0); - else - mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); -} - -void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); -} - -void DialogueWindow::onSelectTopic(const std::string& topic, int id) -{ - if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) - return; - - int separatorPos = 0; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (mTopicsList->getItemNameAt(i) == "") - separatorPos = i; + setVisible(false); } - if (id >= separatorPos) - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); - else + void PersuasionDialog::open() { + WindowModal::open(); + center(); + + int playerGold = MWBase::Environment::get().getWindowManager()->getInventoryWindow()->getPlayerGold(); + + mBribe10Button->setEnabled (playerGold >= 10); + mBribe100Button->setEnabled (playerGold >= 100); + mBribe1000Button->setEnabled (playerGold >= 1000); + + mGoldLabel->setCaptionWithReplacing("#{sGold}: " + boost::lexical_cast(playerGold)); + } + + // -------------------------------------------------------------------------------------------------- + + DialogueWindow::DialogueWindow() + : WindowBase("openmw_dialogue_window.layout") + , mPersuasionDialog() + , mEnabled(false) + , mServices(0) + { + // Centre dialog + center(); + + mPersuasionDialog.setVisible(false); + + //History view + getWidget(mHistory, "History"); + mHistory->setOverflowToTheLeft(true); + mHistory->setMaxTextLength(1000000); + MyGUI::Widget* eventbox; + + //An EditBox cannot receive mouse click events, so we use an + //invisible widget on top of the editbox to receive them + getWidget(eventbox, "EventBox"); + eventbox->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onHistoryClicked); + eventbox->eventMouseWheel += MyGUI::newDelegate(this, &DialogueWindow::onMouseWheel); + + //Topics list + getWidget(mTopicsList, "TopicsList"); + mTopicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); + + MyGUI::Button* byeButton; + getWidget(byeButton, "ByeButton"); + byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); + + getWidget(mDispositionBar, "Disposition"); + getWidget(mDispositionText,"DispositionText"); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &DialogueWindow::onWindowResize); + } + + void DialogueWindow::onHistoryClicked(MyGUI::Widget* _sender) + { + MyGUI::ISubWidgetText* t = mHistory->getClient()->getSubWidgetText(); + if(t == NULL) + return; + + const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + size_t cursorPosition = t->getCursorPosition(lastPressed); + MyGUI::UString color = mHistory->getColorAtPos(cursorPosition); + + if (!mEnabled && color == "#572D21") + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + + if (!mEnabled) + return; + + if(color != "#B29154") + { + MyGUI::UString key = mHistory->getColorTextAt(cursorPosition); + + if(color == "#686EBA") + { + std::map::iterator i = mHyperLinks.upper_bound(cursorPosition); + if( !mHyperLinks.empty() ) + { + --i; + + if( i->first + i->second.mLength > cursorPosition) + { + MWBase::Environment::get().getDialogueManager()->keywordSelected(i->second.mTrueValue); + } + } + else + { + // the link was colored, but it is not in mHyperLinks. + // It means that those liunks are not marked with @# and found + // by topic name search + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(key)); + } + } + + if(color == "#572D21") + MWBase::Environment::get().getDialogueManager()->questionAnswered(lower_string(key)); + } + } + + void DialogueWindow::onWindowResize(MyGUI::Window* _sender) + { + mTopicsList->adjustSize(); + } + + void DialogueWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mHistory->getVScrollPosition() - _rel*0.3 < 0) + mHistory->setVScrollPosition(0); + else + mHistory->setVScrollPosition(mHistory->getVScrollPosition() - _rel*0.3); + } + + void DialogueWindow::onByeClicked(MyGUI::Widget* _sender) + { + MWBase::Environment::get().getDialogueManager()->goodbyeSelected(); + } + + void DialogueWindow::onSelectTopic(const std::string& topic, int id) + { + if (!mEnabled || MWBase::Environment::get().getDialogueManager()->isInChoice()) + return; + + int separatorPos = 0; + for (unsigned int i=0; igetItemCount(); ++i) + { + if (mTopicsList->getItemNameAt(i) == "") + separatorPos = i; + } + + if (id >= separatorPos) + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); + else + { + const MWWorld::Store &gmst = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (topic == gmst.find("sPersuasion")->getString()) + { + mPersuasionDialog.setVisible(true); + } + else if (topic == gmst.find("sCompanionShare")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); + MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + } + else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + { + if (topic == gmst.find("sBarter")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); + } + else if (topic == gmst.find("sSpells")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); + MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); + } + else if (topic == gmst.find("sTravel")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); + MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); + } + else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); + MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); + } + else if (topic == gmst.find("sEnchanting")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); + MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); + } + else if (topic == gmst.find("sServiceTrainingTitle")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); + MWBase::Environment::get().getWindowManager()->startTraining (mPtr); + } + else if (topic == gmst.find("sRepair")->getString()) + { + MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); + MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + } + } + } + } + + void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) + { + mEnabled = true; + mPtr = actor; + mTopicsList->setEnabled(true); + setTitle(npcName); + + mTopicsList->clear(); + mHyperLinks.clear(); + mHistory->setCaption(""); + updateOptions(); + } + + void DialogueWindow::setKeywords(std::list keyWords) + { + mTopicsList->clear(); + + bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() + && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); + + bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); + const MWWorld::Store &gmst = MWBase::Environment::get().getWorld()->getStore().get(); - if (topic == gmst.find("sPersuasion")->getString()) + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + mTopicsList->addItem(gmst.find("sPersuasion")->getString()); + + if (mServices & Service_Trade) + mTopicsList->addItem(gmst.find("sBarter")->getString()); + + if (mServices & Service_BuySpells) + mTopicsList->addItem(gmst.find("sSpells")->getString()); + + if (mServices & Service_Travel) + mTopicsList->addItem(gmst.find("sTravel")->getString()); + + if (mServices & Service_CreateSpells) + mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); + + if (mServices & Service_Enchant) + mTopicsList->addItem(gmst.find("sEnchanting")->getString()); + + if (mServices & Service_Training) + mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); + + if (mServices & Service_Repair) + mTopicsList->addItem(gmst.find("sRepair")->getString()); + + if (isCompanion) + mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); + + if (anyService) + mTopicsList->addSeparator(); + + + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) { - mPersuasionDialog.setVisible(true); + mTopicsList->addItem(*it); } - else if (topic == gmst.find("sCompanionShare")->getString()) + mTopicsList->adjustSize(); + } + + void DialogueWindow::removeKeyword(std::string keyWord) + { + if(mTopicsList->hasItem(keyWord)) { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Companion); - MWBase::Environment::get().getWindowManager()->showCompanionWindow(mPtr); + mTopicsList->removeItem(keyWord); } - else if (!MWBase::Environment::get().getDialogueManager()->checkServiceRefused()) + mTopicsList->adjustSize(); + } + + void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) + { + size_t pos = 0; + while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) { - if (topic == gmst.find("sBarter")->getString()) + // do not add color if this portion of text is already colored. { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Barter); - MWBase::Environment::get().getWindowManager()->getTradeWindow()->startTrade(mPtr); - } - else if (topic == gmst.find("sSpells")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellBuying); - MWBase::Environment::get().getWindowManager()->getSpellBuyingWindow()->startSpellBuying(mPtr); - } - else if (topic == gmst.find("sTravel")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Travel); - MWBase::Environment::get().getWindowManager()->getTravelWindow()->startTravel(mPtr); - } - else if (topic == gmst.find("sSpellMakingMenuTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_SpellCreation); - MWBase::Environment::get().getWindowManager()->startSpellMaking (mPtr); - } - else if (topic == gmst.find("sEnchanting")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Enchanting); - MWBase::Environment::get().getWindowManager()->startEnchanting (mPtr); - } - else if (topic == gmst.find("sServiceTrainingTitle")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Training); - MWBase::Environment::get().getWindowManager()->startTraining (mPtr); - } - else if (topic == gmst.find("sRepair")->getString()) - { - MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_MerchantRepair); - MWBase::Environment::get().getWindowManager()->startRepair (mPtr); + MyGUI::TextIterator iterator (str); + MyGUI::UString colour; + while(iterator.moveNext()) + { + size_t iteratorPos = iterator.getPosition(); + iterator.getTagColour(colour); + if (iteratorPos == pos) + break; + } + + if (colour == color1) + return; } + + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); } } -} -void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) -{ - mEnabled = true; - mPtr = actor; - mTopicsList->setEnabled(true); - setTitle(npcName); - - mTopicsList->clear(); - mHyperLinks.clear(); - mHistory->setCaption(""); - updateOptions(); -} - -void DialogueWindow::setKeywords(std::list keyWords) -{ - mTopicsList->clear(); - - bool isCompanion = !MWWorld::Class::get(mPtr).getScript(mPtr).empty() - && mPtr.getRefData().getLocals().getIntVar(MWWorld::Class::get(mPtr).getScript(mPtr), "companion"); - - bool anyService = mServices > 0 || isCompanion || mPtr.getTypeName() == typeid(ESM::NPC).name(); - - const MWWorld::Store &gmst = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) - mTopicsList->addItem(gmst.find("sPersuasion")->getString()); - - if (mServices & Service_Trade) - mTopicsList->addItem(gmst.find("sBarter")->getString()); - - if (mServices & Service_BuySpells) - mTopicsList->addItem(gmst.find("sSpells")->getString()); - - if (mServices & Service_Travel) - mTopicsList->addItem(gmst.find("sTravel")->getString()); - - if (mServices & Service_CreateSpells) - mTopicsList->addItem(gmst.find("sSpellmakingMenuTitle")->getString()); - - if (mServices & Service_Enchant) - mTopicsList->addItem(gmst.find("sEnchanting")->getString()); - - if (mServices & Service_Training) - mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - - if (mServices & Service_Repair) - mTopicsList->addItem(gmst.find("sRepair")->getString()); - - if (isCompanion) - mTopicsList->addItem(gmst.find("sCompanionShare")->getString()); - - if (anyService) - mTopicsList->addSeparator(); - - - for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) + std::string DialogueWindow::parseText(const std::string& text) { - mTopicsList->addItem(*it); - } - mTopicsList->adjustSize(); -} + bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) -void DialogueWindow::removeKeyword(std::string keyWord) -{ - if(mTopicsList->hasItem(keyWord)) - { - mTopicsList->removeItem(keyWord); - } - mTopicsList->adjustSize(); -} + std::vector topics; -void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) -{ - size_t pos = 0; - while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) - { - // do not add color if this portion of text is already colored. + bool hasSeparator = false; + for (unsigned int i=0; igetItemCount(); ++i) { - MyGUI::TextIterator iterator (str); - MyGUI::UString colour; - while(iterator.moveNext()) - { - size_t iteratorPos = iterator.getPosition(); - iterator.getTagColour(colour); - if (iteratorPos == pos) - break; - } - - if (colour == color1) - return; + if (mTopicsList->getItemNameAt(i) == "") + hasSeparator = true; } - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } -} - -std::string DialogueWindow::parseText(const std::string& text) -{ - bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) - - std::vector topics; - - bool hasSeparator = false; - for (unsigned int i=0; igetItemCount(); ++i) - { - if (mTopicsList->getItemNameAt(i) == "") - hasSeparator = true; - } - - for(unsigned int i = 0;igetItemCount();i++) - { - std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached || !hasSeparator) - topics.push_back(keyWord); - else if (keyWord == "") - separatorReached = true; - } - - // sort by length to make sure longer topics are replaced first - std::sort(topics.begin(), topics.end(), sortByLength); - - std::vector hypertext = MWDialogue::ParseHyperText(text); - - size_t historySize = 0; - if(mHistory->getClient()->getSubWidgetText() != NULL) - { - historySize = mHistory->getOnlyText().size(); - } - - std::string result; - size_t hypertextPos = 0; - for (size_t i = 0; i < hypertext.size(); ++i) - { - if (hypertext[i].mLink) + for(unsigned int i = 0;igetItemCount();i++) { - size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); - std::string standardForm = hypertext[i].mText; - for(; asterisk_count > 0; --asterisk_count) - standardForm.append("*"); + std::string keyWord = mTopicsList->getItemNameAt(i); + if (separatorReached || !hasSeparator) + topics.push_back(keyWord); + else if (keyWord == "") + separatorReached = true; + } - standardForm = - MWBase::Environment::get().getWindowManager()-> - getTranslationDataStorage().topicStandardForm(standardForm); + // sort by length to make sure longer topics are replaced first + std::sort(topics.begin(), topics.end(), sortByLength); - if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + std::vector hypertext = MWDialogue::ParseHyperText(text); + + size_t historySize = 0; + if(mHistory->getClient()->getSubWidgetText() != NULL) + { + historySize = mHistory->getOnlyText().size(); + } + + std::string result; + size_t hypertextPos = 0; + for (size_t i = 0; i < hypertext.size(); ++i) + { + if (hypertext[i].mLink) { - result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + size_t asterisk_count = MWDialogue::RemovePseudoAsterisks(hypertext[i].mText); + std::string standardForm = hypertext[i].mText; + for(; asterisk_count > 0; --asterisk_count) + standardForm.append("*"); - mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); - mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + standardForm = + MWBase::Environment::get().getWindowManager()-> + getTranslationDataStorage().topicStandardForm(standardForm); + + if( std::find(topics.begin(), topics.end(), std::string(standardForm) ) != topics.end() ) + { + result.append("#686EBA").append(hypertext[i].mText).append("#B29154"); + + mHyperLinks[historySize+hypertextPos].mLength = MyGUI::UString(hypertext[i].mText).length(); + mHyperLinks[historySize+hypertextPos].mTrueValue = lower_string(standardForm); + } + else + result += hypertext[i].mText; } else - result += hypertext[i].mText; - } - else - { - if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { - for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + if( !MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation() ) { - addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + { + addColorInString(hypertext[i].mText, *it, "#686EBA", "#B29154"); + } } + + result += hypertext[i].mText; } - result += hypertext[i].mText; + hypertextPos += MyGUI::UString(hypertext[i].mText).length(); } - hypertextPos += MyGUI::UString(hypertext[i].mText).length(); + return result; } - return result; -} - -void DialogueWindow::addText(std::string text) -{ - mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); -} - -void DialogueWindow::addMessageBox(const std::string& text) -{ - mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); -} - -void DialogueWindow::addTitle(std::string text) -{ - // This is called from the dialogue manager, so text is - // case-smashed - thus we have to retrieve the correct case - // of the text through the topic list. - for (size_t i=0; igetItemCount(); ++i) + void DialogueWindow::addText(std::string text) { - std::string item = mTopicsList->getItemNameAt(i); - if (lower_string(item) == text) - text = item; + mHistory->addDialogText("#B29154"+parseText(text)+"#B29154"); } - mHistory->addDialogHeading(text); -} - -void DialogueWindow::askQuestion(std::string question) -{ - mHistory->addDialogText("#572D21"+question+"#B29154"+" "); -} - -void DialogueWindow::updateOptions() -{ - //Clear the list of topics - mTopicsList->clear(); - mHyperLinks.clear(); - mHistory->eraseText(0, mHistory->getTextLength()); - - if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + void DialogueWindow::addMessageBox(const std::string& text) { - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + mHistory->addDialogText("\n#FFFFFF"+text+"#B29154"); } -} -void DialogueWindow::goodbye() -{ - mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); - mTopicsList->setEnabled(false); - mEnabled = false; -} - -void DialogueWindow::onReferenceUnavailable() -{ - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); -} - -void DialogueWindow::onFrame() -{ - if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + void DialogueWindow::addTitle(std::string text) { - int disp = std::max(0, std::min(100, - MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) - + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); - mDispositionBar->setProgressRange(100); - mDispositionBar->setProgressPosition(disp); - mDispositionText->eraseText(0, mDispositionText->getTextLength()); - mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + // This is called from the dialogue manager, so text is + // case-smashed - thus we have to retrieve the correct case + // of the text through the topic list. + for (size_t i=0; igetItemCount(); ++i) + { + std::string item = mTopicsList->getItemNameAt(i); + if (lower_string(item) == text) + text = item; + } + + mHistory->addDialogHeading(text); + } + + void DialogueWindow::askQuestion(std::string question) + { + mHistory->addDialogText("#572D21"+question+"#B29154"+" "); + } + + void DialogueWindow::updateOptions() + { + //Clear the list of topics + mTopicsList->clear(); + mHyperLinks.clear(); + mHistory->eraseText(0, mHistory->getTextLength()); + + if (mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr)); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr))+std::string("/100")+"#B29154"); + } + } + + void DialogueWindow::goodbye() + { + mHistory->addDialogText("\n#572D21" + MWBase::Environment::get().getWorld()->getStore().get().find("sGoodbye")->getString()); + mTopicsList->setEnabled(false); + mEnabled = false; + } + + void DialogueWindow::onReferenceUnavailable() + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); + } + + void DialogueWindow::onFrame() + { + if(mMainWidget->getVisible() && mEnabled && mPtr.getTypeName() == typeid(ESM::NPC).name()) + { + int disp = std::max(0, std::min(100, + MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(mPtr) + + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange())); + mDispositionBar->setProgressRange(100); + mDispositionBar->setProgressPosition(disp); + mDispositionText->eraseText(0, mDispositionText->getTextLength()); + mDispositionText->addText("#B29154"+boost::lexical_cast(disp)+std::string("/100")+"#B29154"); + } } } diff --git a/apps/openmw/mwgui/dialoguehistory.cpp b/apps/openmw/mwgui/dialoguehistory.cpp index a122a78916..d99d55bc12 100644 --- a/apps/openmw/mwgui/dialoguehistory.cpp +++ b/apps/openmw/mwgui/dialoguehistory.cpp @@ -12,65 +12,67 @@ #include #include -using namespace MWGui; -using namespace Widgets; - -MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) +namespace MWGui { - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::TextIterator iterator(getCaption()); - while(iterator.moveNext()) - { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if (pos < _pos) - continue; - else if (pos == _pos) - break; - } - return colour; -} -MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) -{ - bool breakOnNext = false; - MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); - MyGUI::UString colour2 = colour; - MyGUI::TextIterator iterator(getCaption()); - MyGUI::TextIterator col_start = iterator; - while(iterator.moveNext()) + MyGUI::UString DialogueHistory::getColorAtPos(size_t _pos) { - size_t pos = iterator.getPosition(); - iterator.getTagColour(colour); - if(colour != colour2) + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::TextIterator iterator(getCaption()); + while(iterator.moveNext()) { - if(breakOnNext) + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if (pos < _pos) + continue; + else if (pos == _pos) + break; + } + return colour; + } + + MyGUI::UString DialogueHistory::getColorTextAt(size_t _pos) + { + bool breakOnNext = false; + MyGUI::UString colour = MyGUI::TextIterator::convertTagColour(getTextColour()); + MyGUI::UString colour2 = colour; + MyGUI::TextIterator iterator(getCaption()); + MyGUI::TextIterator col_start = iterator; + while(iterator.moveNext()) + { + size_t pos = iterator.getPosition(); + iterator.getTagColour(colour); + if(colour != colour2) { - return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + if(breakOnNext) + { + return getOnlyText().substr(col_start.getPosition(), iterator.getPosition()-col_start.getPosition()); + } + col_start = iterator; + colour2 = colour; + } + if (pos < _pos) + continue; + else if (pos == _pos) + { + breakOnNext = true; } - col_start = iterator; - colour2 = colour; - } - if (pos < _pos) - continue; - else if (pos == _pos) - { - breakOnNext = true; } + return ""; } - return ""; -} -void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) -{ - MyGUI::UString head("\n#D8C09A"); - head.append(parText); - head.append("#B29154\n"); - addText(head); -} + void DialogueHistory::addDialogHeading(const MyGUI::UString& parText) + { + MyGUI::UString head("\n#D8C09A"); + head.append(parText); + head.append("#B29154\n"); + addText(head); + } + + void DialogueHistory::addDialogText(const MyGUI::UString& parText) + { + addText(parText); + addText("\n"); + } -void DialogueHistory::addDialogText(const MyGUI::UString& parText) -{ - addText(parText); - addText("\n"); } diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index b21b903bde..2d72f21740 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -9,8 +9,6 @@ #include #include -using namespace MWGui; - namespace { int convertFromHex(std::string hex) @@ -78,287 +76,292 @@ namespace } } -std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) +namespace MWGui { - using Ogre::UTFString; - std::vector result; - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); - - boost::algorithm::replace_all(utf8Text, "\n", ""); - boost::algorithm::replace_all(utf8Text, "
", "\n"); - boost::algorithm::replace_all(utf8Text, "

", "\n\n"); - - UTFString text(utf8Text); - const int spacing = 48; - - const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); - const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); - const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); - - while (!text.empty()) + std::vector BookTextParser::split(std::string utf8Text, const int width, const int height) { - // read in characters until we have exceeded the size, or run out of text - int currentWidth = 0; - int currentHeight = 0; + using Ogre::UTFString; + std::vector result; - size_t currentWordStart = 0; - size_t index = 0; - while (currentHeight <= height - spacing && index < text.size()) + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + utf8Text = Interpreter::fixDefinesBook(utf8Text, interpreterContext); + + boost::algorithm::replace_all(utf8Text, "\n", ""); + boost::algorithm::replace_all(utf8Text, "
", "\n"); + boost::algorithm::replace_all(utf8Text, "

", "\n\n"); + + UTFString text(utf8Text); + const int spacing = 48; + + const UTFString::unicode_char LEFT_ANGLE = unicodeCharFromChar('<'); + const UTFString::unicode_char NEWLINE = unicodeCharFromChar('\n'); + const UTFString::unicode_char SPACE = unicodeCharFromChar(' '); + + while (!text.empty()) { - const UTFString::unicode_char ch = text.getChar(index); - if (ch == LEFT_ANGLE) - { - const size_t tagStart = index + 1; - const size_t tagEnd = text.find('>', tagStart); - if (tagEnd == UTFString::npos) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); + // read in characters until we have exceeded the size, or run out of text + int currentWidth = 0; + int currentHeight = 0; - if (boost::algorithm::starts_with(tag, "IMG")) + size_t currentWordStart = 0; + size_t index = 0; + while (currentHeight <= height - spacing && index < text.size()) + { + const UTFString::unicode_char ch = text.getChar(index); + if (ch == LEFT_ANGLE) { - const int h = mHeight; - parseImage(tag, false); - currentHeight += (mHeight - h); - currentWidth = 0; - } - else if (boost::algorithm::starts_with(tag, "FONT")) - { - parseFont(tag); - if (currentWidth != 0) { - currentHeight += currentFontHeight(); - currentWidth = 0; - } - currentWidth = 0; - } - else if (boost::algorithm::starts_with(tag, "DIV")) - { - parseDiv(tag); - if (currentWidth != 0) { - currentHeight += currentFontHeight(); - currentWidth = 0; - } - } - index = tagEnd; - } - else if (ch == NEWLINE) - { - currentHeight += currentFontHeight(); - currentWidth = 0; - currentWordStart = index; - } - else if (ch == SPACE) - { - currentWidth += 3; // keep this in sync with the font's SpaceWidth property - currentWordStart = index; - } - else - { - currentWidth += widthForCharGlyph(ch); - } - - if (currentWidth > width) - { - currentHeight += currentFontHeight(); - currentWidth = 0; - // add size of the current word - UTFString word = text.substr(currentWordStart, index - currentWordStart); - for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) - currentWidth += widthForCharGlyph(it.getCharacter()); - } - index += UTFString::_utf16_char_length(ch); - } - const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) - ? currentWordStart : index; - - result.push_back(text.substr(0, pageEnd).asUTF8()); - text.erase(0, pageEnd); - } - - return result; -} - -float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const -{ - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); - return MyGUI::FontManager::getInstance().getByName(fontName) - ->getGlyphInfo(unicodeChar)->width; -} - -float BookTextParser::currentFontHeight() const -{ - std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); - return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); -} - -MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) -{ - MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor - text = Interpreter::fixDefinesBook(text, interpreterContext); - - mParent = parent; - mWidth = width; - mHeight = 0; - - assert(mParent); - while (mParent->getChildCount()) - { - MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); - } - - boost::algorithm::replace_all(text, "\n", ""); - 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 " - if (text[text.size()-1] == '\"') - text.erase(text.size()-1); - - parseSubText(text); - return MyGUI::IntSize(mWidth, mHeight); -} - -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); - - // 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)); - - 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; -} - -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] == '<') - { - const size_t tagStart = 1; - const size_t tagEnd = text.find('>', tagStart); - if (tagEnd == std::string::npos) - throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - const std::string tag = text.substr(tagStart, tagEnd - tagStart); - - if (boost::algorithm::starts_with(tag, "IMG")) - parseImage(tag); - if (boost::algorithm::starts_with(tag, "FONT")) - parseFont(tag); - if (boost::algorithm::starts_with(tag, "DOV")) - parseDiv(tag); - - text.erase(0, tagEnd + 1); - } - - size_t tagStart = std::string::npos; - std::string realText; // real text, without tags - for (size_t i = 0; i= text.size()) + const size_t tagStart = index + 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == UTFString::npos) throw std::runtime_error("BookTextParser Error: Tag is not terminated"); - ++i; - c = text[i]; + const std::string tag = text.substr(tagStart, tagEnd - tagStart).asUTF8(); + + if (boost::algorithm::starts_with(tag, "IMG")) + { + const int h = mHeight; + parseImage(tag, false); + currentHeight += (mHeight - h); + currentWidth = 0; + } + else if (boost::algorithm::starts_with(tag, "FONT")) + { + parseFont(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } + currentWidth = 0; + } + else if (boost::algorithm::starts_with(tag, "DIV")) + { + parseDiv(tag); + if (currentWidth != 0) { + currentHeight += currentFontHeight(); + currentWidth = 0; + } + } + index = tagEnd; + } + else if (ch == NEWLINE) + { + currentHeight += currentFontHeight(); + currentWidth = 0; + currentWordStart = index; + } + else if (ch == SPACE) + { + currentWidth += 3; // keep this in sync with the font's SpaceWidth property + currentWordStart = index; + } + else + { + currentWidth += widthForCharGlyph(ch); + } + + if (currentWidth > width) + { + currentHeight += currentFontHeight(); + currentWidth = 0; + // add size of the current word + UTFString word = text.substr(currentWordStart, index - currentWordStart); + for (UTFString::const_iterator it = word.begin(), end = word.end(); it != end; ++it) + currentWidth += widthForCharGlyph(it.getCharacter()); + } + index += UTFString::_utf16_char_length(ch); + } + const size_t pageEnd = (currentHeight > height - spacing && currentWordStart != 0) + ? currentWordStart : index; + + result.push_back(text.substr(0, pageEnd).asUTF8()); + text.erase(0, pageEnd); + } + + return result; + } + + float BookTextParser::widthForCharGlyph(unsigned unicodeChar) const + { + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName) + ->getGlyphInfo(unicodeChar)->width; + } + + float BookTextParser::currentFontHeight() const + { + std::string fontName(mTextStyle.mFont == "Default" ? "EB Garamond" : mTextStyle.mFont); + return MyGUI::FontManager::getInstance().getByName(fontName)->getDefaultHeight(); + } + + MyGUI::IntSize BookTextParser::parse(std::string text, MyGUI::Widget* parent, const int width) + { + MWScript::InterpreterContext interpreterContext(NULL, MWWorld::Ptr()); // empty arguments, because there is no locals or actor + text = Interpreter::fixDefinesBook(text, interpreterContext); + + mParent = parent; + mWidth = width; + mHeight = 0; + + assert(mParent); + while (mParent->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mParent->getChildAt(0)); + } + + boost::algorithm::replace_all(text, "\n", ""); + 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 " + if (text[text.size()-1] == '\"') + text.erase(text.size()-1); + + parseSubText(text); + return MyGUI::IntSize(mWidth, mHeight); + } + + 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); + + // 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)); + + 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; + } + + 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] == '<') + { + const size_t tagStart = 1; + const size_t tagEnd = text.find('>', tagStart); + if (tagEnd == std::string::npos) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + const std::string tag = text.substr(tagStart, tagEnd - tagStart); + + if (boost::algorithm::starts_with(tag, "IMG")) + parseImage(tag); + if (boost::algorithm::starts_with(tag, "FONT")) + parseFont(tag); + if (boost::algorithm::starts_with(tag, "DOV")) + parseDiv(tag); + + text.erase(0, tagEnd + 1); + } + + size_t tagStart = std::string::npos; + std::string realText; // real text, without tags + for (size_t i = 0; i= text.size()) + throw std::runtime_error("BookTextParser Error: Tag is not terminated"); + ++i; + c = text[i]; + } + continue; + } + else + { + tagStart = i; + break; } - continue; } else - { - tagStart = i; - break; - } + realText += c; + } + + 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; + + if (tagStart != std::string::npos) + { + parseSubText(text.substr(tagStart, text.size())); } - else - realText += c; } - 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; - - if (tagStart != std::string::npos) - { - parseSubText(text.substr(tagStart, text.size())); - } } diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 988bcfc241..59e00bf69d 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -12,528 +12,531 @@ #include "console.hpp" #include "spellicons.hpp" -using namespace MWGui; - -HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) - : Layout("openmw_hud.layout") - , mHealth(NULL) - , mMagicka(NULL) - , mStamina(NULL) - , mWeapImage(NULL) - , mSpellImage(NULL) - , mWeapStatus(NULL) - , mSpellStatus(NULL) - , mEffectBox(NULL) - , mMinimap(NULL) - , mCompass(NULL) - , mCrosshair(NULL) - , mFpsBox(NULL) - , mFpsCounter(NULL) - , mTriangleCounter(NULL) - , mBatchCounter(NULL) - , mHealthManaStaminaBaseLeft(0) - , mWeapBoxBaseLeft(0) - , mSpellBoxBaseLeft(0) - , mEffectBoxBaseRight(0) - , mMinimapBoxBaseRight(0) - , mDragAndDrop(dragAndDrop) - , mCellNameTimer(0.0f) - , mCellNameBox(NULL) - , mMapVisible(true) - , mWeaponVisible(true) - , mSpellVisible(true) - , mWorldMouseOver(false) +namespace MWGui { - setCoord(0,0, width, height); - // Energy bars - getWidget(mHealthFrame, "HealthFrame"); - getWidget(mHealth, "Health"); - getWidget(mMagicka, "Magicka"); - getWidget(mStamina, "Stamina"); - mHealthManaStaminaBaseLeft = mHealthFrame->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); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // Item and spell images and status bars - getWidget(mWeapBox, "WeapBox"); - getWidget(mWeapImage, "WeapImage"); - getWidget(mWeapStatus, "WeapStatus"); - mWeapBoxBaseLeft = mWeapBox->getLeft(); - mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); - - getWidget(mSpellBox, "SpellBox"); - getWidget(mSpellImage, "SpellImage"); - getWidget(mSpellStatus, "SpellStatus"); - mSpellBoxBaseLeft = mSpellBox->getLeft(); - mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); - - getWidget(mEffectBox, "EffectBox"); - mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); - - getWidget(mMinimapBox, "MiniMapBox"); - mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); - getWidget(mMinimap, "MiniMap"); - getWidget(mCompass, "Compass"); - getWidget(mMinimapButton, "MiniMapButton"); - mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); - - getWidget(mCellNameBox, "CellName"); - getWidget(mWeaponSpellBox, "WeaponSpellName"); - - getWidget(mCrosshair, "Crosshair"); - - setFpsLevel(fpsLevel); - - getWidget(mTriangleCounter, "TriangleCounter"); - getWidget(mBatchCounter, "BatchCounter"); - - LocalMapBase::init(mMinimap, mCompass, this); - - mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); - mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); - mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); - - mSpellIcons = new SpellIcons(); -} - -HUD::~HUD() -{ - delete mSpellIcons; -} - -void HUD::setFpsLevel(int level) -{ - mFpsCounter = 0; - - MyGUI::Widget* fps; - getWidget(fps, "FPSBoxAdv"); - fps->setVisible(false); - getWidget(fps, "FPSBox"); - fps->setVisible(false); - - if (level == 2) + HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) + : Layout("openmw_hud.layout") + , mHealth(NULL) + , mMagicka(NULL) + , mStamina(NULL) + , mWeapImage(NULL) + , mSpellImage(NULL) + , mWeapStatus(NULL) + , mSpellStatus(NULL) + , mEffectBox(NULL) + , mMinimap(NULL) + , mCompass(NULL) + , mCrosshair(NULL) + , mFpsBox(NULL) + , mFpsCounter(NULL) + , mTriangleCounter(NULL) + , mBatchCounter(NULL) + , mHealthManaStaminaBaseLeft(0) + , mWeapBoxBaseLeft(0) + , mSpellBoxBaseLeft(0) + , mEffectBoxBaseRight(0) + , mMinimapBoxBaseRight(0) + , mDragAndDrop(dragAndDrop) + , mCellNameTimer(0.0f) + , mCellNameBox(NULL) + , mMapVisible(true) + , mWeaponVisible(true) + , mSpellVisible(true) + , mWorldMouseOver(false) { - getWidget(mFpsBox, "FPSBoxAdv"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounterAdv"); + setCoord(0,0, width, height); + + // Energy bars + getWidget(mHealthFrame, "HealthFrame"); + getWidget(mHealth, "Health"); + getWidget(mMagicka, "Magicka"); + getWidget(mStamina, "Stamina"); + mHealthManaStaminaBaseLeft = mHealthFrame->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); + + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // Item and spell images and status bars + getWidget(mWeapBox, "WeapBox"); + getWidget(mWeapImage, "WeapImage"); + getWidget(mWeapStatus, "WeapStatus"); + mWeapBoxBaseLeft = mWeapBox->getLeft(); + mWeapBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWeaponClicked); + + getWidget(mSpellBox, "SpellBox"); + getWidget(mSpellImage, "SpellImage"); + getWidget(mSpellStatus, "SpellStatus"); + mSpellBoxBaseLeft = mSpellBox->getLeft(); + mSpellBox->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMagicClicked); + + getWidget(mEffectBox, "EffectBox"); + mEffectBoxBaseRight = viewSize.width - mEffectBox->getRight(); + + getWidget(mMinimapBox, "MiniMapBox"); + mMinimapBoxBaseRight = viewSize.width - mMinimapBox->getRight(); + getWidget(mMinimap, "MiniMap"); + getWidget(mCompass, "Compass"); + getWidget(mMinimapButton, "MiniMapButton"); + mMinimapButton->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onMapClicked); + + getWidget(mCellNameBox, "CellName"); + getWidget(mWeaponSpellBox, "WeaponSpellName"); + + getWidget(mCrosshair, "Crosshair"); + + setFpsLevel(fpsLevel); + + getWidget(mTriangleCounter, "TriangleCounter"); + getWidget(mBatchCounter, "BatchCounter"); + + LocalMapBase::init(mMinimap, mCompass, this); + + mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); + mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); + mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); + + mSpellIcons = new SpellIcons(); } - else if (level == 1) + + HUD::~HUD() { - getWidget(mFpsBox, "FPSBox"); - mFpsBox->setVisible(true); - getWidget(mFpsCounter, "FPSCounter"); + delete mSpellIcons; } -} -void HUD::setFPS(float fps) -{ - if (mFpsCounter) - mFpsCounter->setCaption(boost::lexical_cast((int)fps)); -} - -void HUD::setTriangleCount(unsigned int count) -{ - mTriangleCounter->setCaption(boost::lexical_cast(count)); -} - -void HUD::setBatchCount(unsigned int count) -{ - mBatchCounter->setCaption(boost::lexical_cast(count)); -} - -void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = + void HUD::setFpsLevel(int level) { - "HBar", "MBar", "FBar", 0 - }; + mFpsCounter = 0; - for (int i=0; ids[i]; ++i) - if (ids[i]==id) + MyGUI::Widget* fps; + getWidget(fps, "FPSBoxAdv"); + fps->setVisible(false); + getWidget(fps, "FPSBox"); + fps->setVisible(false); + + if (level == 2) { - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - switch (i) - { - case 0: - mHealth->setProgressRange (value.getModified()); - mHealth->setProgressPosition (value.getCurrent()); - getWidget(w, "HealthFrame"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); - break; - case 1: - mMagicka->setProgressRange (value.getModified()); - mMagicka->setProgressPosition (value.getCurrent()); - getWidget(w, "MagickaFrame"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - break; - case 2: - mStamina->setProgressRange (value.getModified()); - mStamina->setProgressPosition (value.getCurrent()); - getWidget(w, "FatigueFrame"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); - break; - } + getWidget(mFpsBox, "FPSBoxAdv"); + mFpsBox->setVisible(true); + getWidget(mFpsCounter, "FPSCounterAdv"); + } + else if (level == 1) + { + getWidget(mFpsBox, "FPSBox"); + mFpsBox->setVisible(true); + getWidget(mFpsCounter, "FPSCounter"); } -} - -void HUD::onWorldClicked(MyGUI::Widget* _sender) -{ - if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) - return; - - if (mDragAndDrop->mIsOnDragAndDrop) - { - // drop item into the gameworld - MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); - - MWBase::World* world = MWBase::Environment::get().getWorld(); - - 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); - - int origCount = object.getRefData().getCount(); - object.getRefData().setCount(mDragAndDrop->mDraggedCount); - - if (world->canPlaceObject(mouseX, mouseY)) - world->placeObject(object, mouseX, mouseY); - else - world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - - MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - - std::string sound = MWWorld::Class::get(object).getDownSoundId(object); - MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - - // remove object from the container it was coming from - object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); - - mDragAndDrop->mIsOnDragAndDrop = false; - MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget = 0; - - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - mDragAndDrop->mDraggedFrom->drawItems(); - mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); } - else - { - GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); - if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + void HUD::setFPS(float fps) + { + if (mFpsCounter) + mFpsCounter->setCaption(boost::lexical_cast((int)fps)); + } + + void HUD::setTriangleCount(unsigned int count) + { + mTriangleCounter->setCaption(boost::lexical_cast(count)); + } + + void HUD::setBatchCount(unsigned int count) + { + mBatchCounter->setCaption(boost::lexical_cast(count)); + } + + void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) + { + static const char *ids[] = + { + "HBar", "MBar", "FBar", 0 + }; + + 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: + mHealth->setProgressRange (value.getModified()); + mHealth->setProgressPosition (value.getCurrent()); + getWidget(w, "HealthFrame"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + break; + case 1: + mMagicka->setProgressRange (value.getModified()); + mMagicka->setProgressPosition (value.getCurrent()); + getWidget(w, "MagickaFrame"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + break; + case 2: + mStamina->setProgressRange (value.getModified()); + mStamina->setProgressPosition (value.getCurrent()); + getWidget(w, "FatigueFrame"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + break; + } + } + } + + void HUD::onWorldClicked(MyGUI::Widget* _sender) + { + if (!MWBase::Environment::get().getWindowManager ()->isGuiMode ()) return; - MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); - - if (mode == GM_Console) - MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); - else if ((mode == GM_Container) || (mode == GM_Inventory)) + if (mDragAndDrop->mIsOnDragAndDrop) { - // pick up object - MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); - } - } -} + // drop item into the gameworld + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); -void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) -{ - if (mDragAndDrop->mIsOnDragAndDrop) - { - mWorldMouseOver = false; + MWBase::World* world = MWBase::Environment::get().getWorld(); - 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); + 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::World* world = MWBase::Environment::get().getWorld(); + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(mDragAndDrop->mDraggedCount); - // if we can't drop the object at the wanted position, show the "drop on ground" cursor. - bool canDrop = world->canPlaceObject(mouseX, mouseY); + if (world->canPlaceObject(mouseX, mouseY)) + world->placeObject(object, mouseX, mouseY); + else + world->dropObjectOnGround(world->getPlayer().getPlayer(), object); - if (!canDrop) - MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); - else MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + // remove object from the container it was coming from + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget = 0; + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + mDragAndDrop->mDraggedFrom->drawItems(); + mDragAndDrop->mDraggedFrom->notifyItemDragged(object, -mDragAndDrop->mDraggedCount); + } + else + { + GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode(); + + if ( (mode != GM_Console) && (mode != GM_Container) && (mode != GM_Inventory) ) + return; + + MWWorld::Ptr object = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (mode == GM_Console) + MWBase::Environment::get().getWindowManager()->getConsole()->setSelectedObject(object); + else if ((mode == GM_Container) || (mode == GM_Inventory)) + { + // pick up object + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->pickUpObject(object); + } + } } - else + + 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); + float mouseY = cursorPosition.top / float(viewSize.height); + + MWBase::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) + MWBase::Environment::get().getWindowManager()->changePointer("drop_ground"); + else + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + + } + else + { + MWBase::Environment::get().getWindowManager()->changePointer("arrow"); + mWorldMouseOver = true; + } + } + + void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) { MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - mWorldMouseOver = true; - } -} - -void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) -{ - MWBase::Environment::get().getWindowManager()->changePointer("arrow"); - mWorldMouseOver = false; -} - -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); -} - -void HUD::setCellName(const std::string& cellName) -{ - if (mCellName != cellName) - { - mCellNameTimer = 5.0f; - mCellName = cellName; - - mCellNameBox->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); - mCellNameBox->setVisible(mMapVisible); - } -} - -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().get().find(spellId); - - std::string spellName = spell->mName; - if (spellName != mSpellName && mSpellVisible) - { - mWeaponSpellTimer = 5.0f; - mSpellName = spellName; - mWeaponSpellBox->setCaption(mSpellName); - mWeaponSpellBox->setVisible(true); + mWorldMouseOver = false; } - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(successChancePercent); - - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - - mSpellBox->setUserString("ToolTipType", "Spell"); - mSpellBox->setUserString("Spell", spellId); - - // use the icon of the first effect - const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); - - std::string icon = effect->mIcon; - int slashPos = icon.find("\\"); - icon.insert(slashPos+1, "b_"); - icon = std::string("icons\\") + icon; - Widgets::fixTexturePath(icon); - mSpellImage->setImageTexture(icon); -} - -void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) -{ - std::string itemName = MWWorld::Class::get(item).getName(item); - if (itemName != mSpellName && mSpellVisible) + void HUD::onHMSClicked(MyGUI::Widget* _sender) { - mWeaponSpellTimer = 5.0f; - mSpellName = itemName; - mWeaponSpellBox->setCaption(mSpellName); - mWeaponSpellBox->setVisible(true); + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Stats); } - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(chargePercent); - - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - - mSpellBox->setUserString("ToolTipType", "ItemPtr"); - mSpellBox->setUserData(item); - - mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mSpellImage->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 && mWeaponVisible) + void HUD::onMapClicked(MyGUI::Widget* _sender) { - mWeaponSpellTimer = 5.0f; - mWeaponName = itemName; - mWeaponSpellBox->setCaption(mWeaponName); - mWeaponSpellBox->setVisible(true); + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Map); } - mWeapBox->setUserString("ToolTipType", "ItemPtr"); - mWeapBox->setUserData(item); - - mWeapStatus->setProgressRange(100); - mWeapStatus->setProgressPosition(durabilityPercent); - - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->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) != "") + void HUD::onWeaponClicked(MyGUI::Widget* _sender) { - mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); - MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + MWBase::Environment::get().getWindowManager()->toggleVisible(GW_Inventory); + } + + 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->setCaptionWithReplacing("#{sCell=" + mCellName + "}"); + mCellNameBox->setVisible(mMapVisible); + } + } + + 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().get().find(spellId); + + std::string spellName = spell->mName; + if (spellName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(successChancePercent); + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + + mSpellBox->setUserString("ToolTipType", "Spell"); + mSpellBox->setUserString("Spell", spellId); + + // use the icon of the first effect + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld()->getStore().get().find(spell->mEffects.mList.front().mEffectID); + + std::string icon = effect->mIcon; + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + icon = std::string("icons\\") + icon; + Widgets::fixTexturePath(icon); + mSpellImage->setImageTexture(icon); + } + + void HUD::setSelectedEnchantItem(const MWWorld::Ptr& item, int chargePercent) + { + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = itemName; + mWeaponSpellBox->setCaption(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(chargePercent); + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + + mSpellBox->setUserString("ToolTipType", "ItemPtr"); + mSpellBox->setUserData(item); + + mSpellImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mSpellImage->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); } - else - mWeapImage->setImageTexture(path); -} -void HUD::unsetSelectedSpell() -{ - std::string spellName = "#{sNone}"; - if (spellName != mSpellName && mSpellVisible) + void HUD::setSelectedWeapon(const MWWorld::Ptr& item, int durabilityPercent) { - mWeaponSpellTimer = 5.0f; - mSpellName = spellName; - mWeaponSpellBox->setCaptionWithReplacing(mSpellName); - mWeaponSpellBox->setVisible(true); + std::string itemName = MWWorld::Class::get(item).getName(item); + if (itemName != mWeaponName && mWeaponVisible) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaption(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + mWeapBox->setUserString("ToolTipType", "ItemPtr"); + mWeapBox->setUserData(item); + + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(durabilityPercent); + + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->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) != "") + { + mWeapImage->setImageTexture("textures\\menu_icon_magic_mini.dds"); + MyGUI::ImageBox* itemBox = mWeapImage->createWidgetReal("ImageBox", MyGUI::FloatCoord(0,0,1,1) + , MyGUI::Align::Stretch); + itemBox->setImageTexture(path); + itemBox->setNeedMouseFocus(false); + } + else + mWeapImage->setImageTexture(path); } - if (mSpellImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); - mSpellStatus->setProgressRange(100); - mSpellStatus->setProgressPosition(0); - mSpellImage->setImageTexture(""); - mSpellBox->clearUserStrings(); -} - -void HUD::unsetSelectedWeapon() -{ - std::string itemName = "#{sSkillHandtohand}"; - if (itemName != mWeaponName && mWeaponVisible) + void HUD::unsetSelectedSpell() { - mWeaponSpellTimer = 5.0f; - mWeaponName = itemName; - mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); - mWeaponSpellBox->setVisible(true); + std::string spellName = "#{sNone}"; + if (spellName != mSpellName && mSpellVisible) + { + mWeaponSpellTimer = 5.0f; + mSpellName = spellName; + mWeaponSpellBox->setCaptionWithReplacing(mSpellName); + mWeaponSpellBox->setVisible(true); + } + + if (mSpellImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mSpellImage->getChildAt(0)); + mSpellStatus->setProgressRange(100); + mSpellStatus->setProgressPosition(0); + mSpellImage->setImageTexture(""); + mSpellBox->clearUserStrings(); + } + + void HUD::unsetSelectedWeapon() + { + std::string itemName = "#{sSkillHandtohand}"; + if (itemName != mWeaponName && mWeaponVisible) + { + mWeaponSpellTimer = 5.0f; + mWeaponName = itemName; + mWeaponSpellBox->setCaptionWithReplacing(mWeaponName); + mWeaponSpellBox->setVisible(true); + } + + if (mWeapImage->getChildCount()) + MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); + mWeapStatus->setProgressRange(100); + mWeapStatus->setProgressPosition(0); + mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); + mWeapBox->clearUserStrings(); + } + + void HUD::setCrosshairVisible(bool visible) + { + mCrosshair->setVisible (visible); + } + + void HUD::setHmsVisible(bool visible) + { + mHealth->setVisible(visible); + mMagicka->setVisible(visible); + mStamina->setVisible(visible); + updatePositions(); + } + + void HUD::setWeapVisible(bool visible) + { + mWeapBox->setVisible(visible); + updatePositions(); + } + + void HUD::setSpellVisible(bool visible) + { + mSpellBox->setVisible(visible); + updatePositions(); + } + + void HUD::setEffectVisible(bool visible) + { + mEffectBox->setVisible (visible); + updatePositions(); + } + + void HUD::setMinimapVisible(bool visible) + { + mMinimapBox->setVisible (visible); + updatePositions(); + } + + void HUD::updatePositions() + { + int weapDx = 0, spellDx = 0; + if (!mHealth->getVisible()) + spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; + + if (!mWeapBox->getVisible()) + spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; + + mWeaponVisible = mWeapBox->getVisible(); + mSpellVisible = mSpellBox->getVisible(); + if (!mWeaponVisible && !mSpellVisible) + mWeaponSpellBox->setVisible(false); + + mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); + mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); + + const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + // effect box can have variable width -> variable left coordinate + int effectsDx = 0; + if (!mMinimapBox->getVisible ()) + effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); + + mMapVisible = mMinimapBox->getVisible (); + mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); + } + + void HUD::update() + { + mSpellIcons->updateWidgets(mEffectBox, true); } - if (mWeapImage->getChildCount()) - MyGUI::Gui::getInstance().destroyWidget(mWeapImage->getChildAt(0)); - mWeapStatus->setProgressRange(100); - mWeapStatus->setProgressPosition(0); - mWeapImage->setImageTexture("icons\\k\\stealth_handtohand.dds"); - mWeapBox->clearUserStrings(); -} - -void HUD::setCrosshairVisible(bool visible) -{ - mCrosshair->setVisible (visible); -} - -void HUD::setHmsVisible(bool visible) -{ - mHealth->setVisible(visible); - mMagicka->setVisible(visible); - mStamina->setVisible(visible); - updatePositions(); -} - -void HUD::setWeapVisible(bool visible) -{ - mWeapBox->setVisible(visible); - updatePositions(); -} - -void HUD::setSpellVisible(bool visible) -{ - mSpellBox->setVisible(visible); - updatePositions(); -} - -void HUD::setEffectVisible(bool visible) -{ - mEffectBox->setVisible (visible); - updatePositions(); -} - -void HUD::setMinimapVisible(bool visible) -{ - mMinimapBox->setVisible (visible); - updatePositions(); -} - -void HUD::updatePositions() -{ - int weapDx = 0, spellDx = 0; - if (!mHealth->getVisible()) - spellDx = weapDx = mWeapBoxBaseLeft - mHealthManaStaminaBaseLeft; - - if (!mWeapBox->getVisible()) - spellDx += mSpellBoxBaseLeft - mWeapBoxBaseLeft; - - mWeaponVisible = mWeapBox->getVisible(); - mSpellVisible = mSpellBox->getVisible(); - if (!mWeaponVisible && !mSpellVisible) - mWeaponSpellBox->setVisible(false); - - mWeapBox->setPosition(mWeapBoxBaseLeft - weapDx, mWeapBox->getTop()); - mSpellBox->setPosition(mSpellBoxBaseLeft - spellDx, mSpellBox->getTop()); - - const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize(); - - // effect box can have variable width -> variable left coordinate - int effectsDx = 0; - if (!mMinimapBox->getVisible ()) - effectsDx = (viewSize.width - mMinimapBoxBaseRight) - (viewSize.width - mEffectBoxBaseRight); - - mMapVisible = mMinimapBox->getVisible (); - mEffectBox->setPosition((viewSize.width - mEffectBoxBaseRight) - mEffectBox->getWidth() + effectsDx, mEffectBox->getTop()); -} - -void HUD::update() -{ - mSpellIcons->updateWidgets(mEffectBox, true); } diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index c7b7207305..8dda041ca6 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -5,159 +5,165 @@ #include #include -using namespace MWGui; -using namespace MWGui::Widgets; - -MWList::MWList() : - mClient(0) - , mScrollView(0) - , mItemHeight(0) +namespace MWGui { -} -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); -} - -void MWList::addSeparator() -{ - mItems.push_back(""); -} - -void MWList::adjustSize() -{ - redraw(); -} - -void MWList::redraw(bool scrollbarShown) -{ - const int _scrollBarWidth = 24; // fetch this from skin? - const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; - const int spacing = 3; - size_t scrollbarPosition = mScrollView->getScrollPosition(); - - while (mScrollView->getChildCount()) + namespace Widgets { - MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); - } - mItemHeight = 0; - int i=0; - for (std::vector::const_iterator it=mItems.begin(); - it!=mItems.end(); ++it) - { - if (*it != "") + MWList::MWList() : + mClient(0) + , mScrollView(0) + , mItemHeight(0) { - 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)); - button->setUserData(i); - - mItemHeight += height + spacing; } - else + + void MWList::initialiseOverride() { - 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); + Base::initialiseOverride(); - mItemHeight += 18 + spacing; + 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"); } - ++i; + + void MWList::addItem(const std::string& name) + { + mItems.push_back(name); + } + + void MWList::addSeparator() + { + mItems.push_back(""); + } + + void MWList::adjustSize() + { + redraw(); + } + + void MWList::redraw(bool scrollbarShown) + { + const int _scrollBarWidth = 24; // fetch this from skin? + const int scrollBarWidth = scrollbarShown ? _scrollBarWidth : 0; + const int spacing = 3; + size_t scrollbarPosition = mScrollView->getScrollPosition(); + + while (mScrollView->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mScrollView->getChildAt(0)); + } + + mItemHeight = 0; + int i=0; + for (std::vector::const_iterator it=mItems.begin(); + it!=mItems.end(); ++it) + { + 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)); + button->setUserData(i); + + 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; + } + ++i; + } + mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); + + if (!scrollbarShown && mItemHeight > mClient->getSize().height) + redraw(true); + + size_t scrollbarRange = mScrollView->getScrollRange(); + if(scrollbarPosition > scrollbarRange) + scrollbarPosition = scrollbarRange; + mScrollView->setScrollPosition(scrollbarPosition); + } + + 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) ); + } + + void MWList::clear() + { + mItems.clear(); + } + + 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(); + int id = *_sender->getUserData(); + eventItemSelected(name, id); + eventWidgetSelected(_sender); + } + + MyGUI::Widget* MWList::getItemWidget(const std::string& name) + { + return mScrollView->findWidget (getName() + "_item_" + name); + } + + size_t MWScrollView::getScrollPosition() + { + return getVScroll()->getScrollPosition(); + } + + void MWScrollView::setScrollPosition(size_t position) + { + getVScroll()->setScrollPosition(position); + } + size_t MWScrollView::getScrollRange() + { + return getVScroll()->getScrollRange(); + } + } - mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); - - if (!scrollbarShown && mItemHeight > mClient->getSize().height) - redraw(true); - - size_t scrollbarRange = mScrollView->getScrollRange(); - if(scrollbarPosition > scrollbarRange) - scrollbarPosition = scrollbarRange; - mScrollView->setScrollPosition(scrollbarPosition); -} - -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) ); -} - -void MWList::clear() -{ - mItems.clear(); -} - -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(); - int id = *_sender->getUserData(); - eventItemSelected(name, id); - eventWidgetSelected(_sender); -} - -MyGUI::Widget* MWList::getItemWidget(const std::string& name) -{ - return mScrollView->findWidget (getName() + "_item_" + name); -} - -size_t MWScrollView::getScrollPosition() -{ - return getVScroll()->getScrollPosition(); -} - -void MWScrollView::setScrollPosition(size_t position) -{ - getVScroll()->setScrollPosition(position); -} -size_t MWScrollView::getScrollRange() -{ - return getVScroll()->getScrollRange(); } diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 1ac1c24480..4a78238ce0 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -13,430 +13,433 @@ #include "widgets.hpp" -using namespace MWGui; - -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mMapDragAndDrop(false) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) - , mCompass(NULL) +namespace MWGui { -} -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) + LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mMapDragAndDrop(false) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) + , mCompass(NULL) { - for (int my=0; my<3; ++my) + } + + 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) { - 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) + for (int my=0; my<3; ++my) { - map->setNeedMouseFocus(false); - fog->setNeedMouseFocus(false); - } + 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)); - mMapWidgets.push_back(map); - mFogWidgets.push_back(fog); - } - } -} + 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"); -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 + (-1*(my-1))); - MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } - } - notifyMapChanged (); -} - -void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) -{ - applyFogOfWar (); -} - -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 - - // clear all previous markers - for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) - { - if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") - { - MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); - } - } - - for (int mx=0; mx<3; ++mx) - { - for (int my=0; my<3; ++my) - { - // map - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (-1*(my-1))); - - 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); - else - box->setImageTexture("black.png"); - - - // door markers - - // interior map only consists of one cell, so handle the markers only once - if (interior && (mx != 2 || my != 2)) - continue; - - MWWorld::CellStore* cell; - if (interior) - cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); - else - cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); - - std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); - - for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) - { - MWBase::World::DoorMarker marker = *it; - - // convert world coordinates to normalized cell coordinates - MyGUI::IntCoord widgetCoord; - float nX,nY; - int cellDx, cellDy; - if (!interior) + if (!mMapDragAndDrop) { - const int cellSize = 8192; - - nX = (marker.x - cellSize * (x+mx-1)) / cellSize; - nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; - - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + map->setNeedMouseFocus(false); + fog->setNeedMouseFocus(false); } + + mMapWidgets.push_back(map); + mFogWidgets.push_back(fog); + } + } + } + + 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 + (-1*(my-1))); + MyGUI::ImageBox* fog = mFogWidgets[my + 3*mx]; + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } + notifyMapChanged (); + } + + void LocalMapBase::onMarkerFocused (MyGUI::Widget* w1, MyGUI::Widget* w2) + { + applyFogOfWar (); + } + + void LocalMapBase::onMarkerUnfocused (MyGUI::Widget* w1, MyGUI::Widget* w2) + { + applyFogOfWar (); + } + + 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 + + // clear all previous markers + for (unsigned int i=0; i< mLocalMap->getChildCount(); ++i) + { + if (mLocalMap->getChildAt(i)->getName ().substr (0, 6) == "Marker") + { + MyGUI::Gui::getInstance ().destroyWidget (mLocalMap->getChildAt(i)); + } + } + + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + // map + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (-1*(my-1))); + + 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); else - { - Ogre::Vector2 position (marker.x, marker.y); - MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + box->setImageTexture("black.png"); - widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + + // door markers + + // interior map only consists of one cell, so handle the markers only once + if (interior && (mx != 2 || my != 2)) + continue; + + MWWorld::CellStore* cell; + if (interior) + cell = MWBase::Environment::get().getWorld ()->getInterior (mPrefix); + else + cell = MWBase::Environment::get().getWorld ()->getExterior (x+mx-1, y-(my-1)); + + std::vector doors = MWBase::Environment::get().getWorld ()->getDoorMarkers (cell); + + for (std::vector::iterator it = doors.begin(); it != doors.end(); ++it) + { + MWBase::World::DoorMarker marker = *it; + + // convert world coordinates to normalized cell coordinates + MyGUI::IntCoord widgetCoord; + float nX,nY; + int cellDx, cellDy; + if (!interior) + { + const int cellSize = 8192; + + nX = (marker.x - cellSize * (x+mx-1)) / cellSize; + nY = 1 - (marker.y - cellSize * (y-(my-1))) / cellSize; + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + mx * 512, nY * 512 - 4 + my * 512, 8, 8); + } + else + { + Ogre::Vector2 position (marker.x, marker.y); + MWBase::Environment::get().getWorld ()->getInteriorMapPosition (position, nX, nY, cellDx, cellDy); + + widgetCoord = MyGUI::IntCoord(nX * 512 - 4 + (1+cellDx-x) * 512, nY * 512 - 4 + (1+cellDy-y) * 512, 8, 8); + } + + static int counter = 0; + ++counter; + MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", marker.name); + markerWidget->setUserString("IsMarker", "true"); + markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); + markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); + + MarkerPosition markerPos; + markerPos.interior = interior; + markerPos.cellX = interior ? cellDx : x + mx - 1; + markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); + markerPos.nX = nX; + markerPos.nY = nY; + + markerWidget->setUserData(markerPos); } - static int counter = 0; - ++counter; - MyGUI::Button* markerWidget = mLocalMap->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", marker.name); - markerWidget->setUserString("IsMarker", "true"); - markerWidget->eventMouseSetFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerFocused); - markerWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &LocalMapBase::onMarkerUnfocused); - MarkerPosition markerPos; - markerPos.interior = interior; - markerPos.cellX = interior ? cellDx : x + mx - 1; - markerPos.cellY = interior ? cellDy : y + ((my - 1)*-1); - markerPos.nX = nX; - markerPos.nY = nY; - - markerWidget->setUserData(markerPos); } - - } - } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; - // fog of war - applyFogOfWar(); + // fog of war + 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; - - notifyPlayerUpdate (); - - 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; - - notifyPlayerUpdate (); - - 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; -} - -// ------------------------------------------------------------------------------------------ - -MapWindow::MapWindow(const std::string& cacheDir) - : MWGui::WindowPinnableBase("openmw_map_window.layout") - , mGlobal(false) -{ - setCoord(500,0,320,300); - - mGlobalMapRender = new MWRender::GlobalMap(cacheDir); - mGlobalMapRender->render(); - - getWidget(mLocalMap, "LocalMap"); - getWidget(mGlobalMap, "GlobalMap"); - getWidget(mGlobalMapImage, "GlobalMapImage"); - getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); - getWidget(mPlayerArrowLocal, "CompassLocal"); - getWidget(mPlayerArrowGlobal, "CompassGlobal"); - - mGlobalMapImage->setImageTexture("GlobalMap.png"); - mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); - - mGlobalMap->setVisible (false); - - getWidget(mButton, "WorldButton"); - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing("#{sWorld}"); - - getWidget(mEventBoxGlobal, "EventBoxGlobal"); - mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - getWidget(mEventBoxLocal, "EventBoxLocal"); - mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); - - LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); -} - -MapWindow::~MapWindow() -{ - delete mGlobalMapRender; -} - -void MapWindow::setCellName(const std::string& cellName) -{ - setTitle("#{sCell=" + cellName + "}"); -} - -void MapWindow::addVisitedLocation(const std::string& name, int x, int y) -{ - float worldX, worldY; - mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); - - MyGUI::IntCoord widgetCoord( - worldX * mGlobalMapRender->getWidth()+6, - worldY * mGlobalMapRender->getHeight()+6, - 12, 12); - - - static int _counter=0; - MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", - widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); - markerWidget->setImageResource("DoorMarker"); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); - ++_counter; - - markerWidget = mEventBoxGlobal->createWidget("", - widgetCoord, MyGUI::Align::Default); - markerWidget->setNeedMouseFocus (true); - markerWidget->setUserString("ToolTipType", "Layout"); - markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); - markerWidget->setUserString("Caption_TextOneLine", name); -} - -void MapWindow::cellExplored(int x, int y) -{ - mGlobalMapRender->exploreCell(x,y); -} - -void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) -{ - if (_id!=MyGUI::MouseButton::Left) return; - - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - - if (!mGlobal) - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); - else - mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); - - - mLastDragPos = MyGUI::IntPoint(_left, _top); -} - -void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) -{ - mGlobal = !mGlobal; - mGlobalMap->setVisible(mGlobal); - mLocalMap->setVisible(!mGlobal); - - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); - - if (mGlobal) - globalMapUpdatePlayer (); -} - -void MapWindow::onPinToggled() -{ - MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); -} - -void MapWindow::open() -{ - mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); - - for (unsigned int i=0; igetChildCount (); ++i) - { - if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") - mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + // 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); } - globalMapUpdatePlayer(); - mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); -} - -void MapWindow::globalMapUpdatePlayer () -{ - Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); - Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); - Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); - - float worldX, worldY; - mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); - worldX *= mGlobalMapRender->getWidth(); - worldY *= mGlobalMapRender->getHeight(); - - - // for interiors, we have no choice other than using the last position & direction. - /// \todo save this last position in the savegame? - if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + void LocalMapBase::setPlayerPos(const float x, const float y) { - mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + if (x == mLastPositionX && y == mLastPositionY) + return; - MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + notifyPlayerUpdate (); + + 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; + + notifyPlayerUpdate (); + + MyGUI::ISubWidget* main = mCompass->getSubWidgetMain(); MyGUI::RotatingSkin* rotatingSubskin = main->castType(); rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); - float angle = std::atan2(dir.x, dir.y); + float angle = std::atan2(x,y); rotatingSubskin->setAngle(angle); - // set the view offset so that player is in the center - MyGUI::IntSize viewsize = mGlobalMap->getSize(); - MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); - mGlobalMap->setViewOffset(viewoffs); + mLastDirectionX = x; + mLastDirectionY = y; } -} -void MapWindow::notifyPlayerUpdate () -{ - globalMapUpdatePlayer (); -} + // ------------------------------------------------------------------------------------------ -void MapWindow::notifyMapChanged () -{ - // workaround to prevent the map from drawing on top of the button - MyGUI::IntCoord oldCoord = mButton->getCoord (); - MyGUI::Gui::getInstance().destroyWidget (mButton); - mButton = mMainWidget->createWidget("MW_Button", - oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); - mButton->setProperty ("ExpandDirection", "Left"); + MapWindow::MapWindow(const std::string& cacheDir) + : MWGui::WindowPinnableBase("openmw_map_window.layout") + , mGlobal(false) + { + setCoord(500,0,320,300); + + mGlobalMapRender = new MWRender::GlobalMap(cacheDir); + mGlobalMapRender->render(); + + getWidget(mLocalMap, "LocalMap"); + getWidget(mGlobalMap, "GlobalMap"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mGlobalMapOverlay, "GlobalMapOverlay"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMapImage->setImageTexture("GlobalMap.png"); + mGlobalMapOverlay->setImageTexture("GlobalMapOverlay"); + + mGlobalMap->setVisible (false); + + getWidget(mButton, "WorldButton"); + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing("#{sWorld}"); + + getWidget(mEventBoxGlobal, "EventBoxGlobal"); + mEventBoxGlobal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxGlobal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + getWidget(mEventBoxLocal, "EventBoxLocal"); + mEventBoxLocal->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); + mEventBoxLocal->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); + } + + MapWindow::~MapWindow() + { + delete mGlobalMapRender; + } + + void MapWindow::setCellName(const std::string& cellName) + { + setTitle("#{sCell=" + cellName + "}"); + } + + void MapWindow::addVisitedLocation(const std::string& name, int x, int y) + { + float worldX, worldY; + mGlobalMapRender->cellTopLeftCornerToImageSpace (x, y, worldX, worldY); + + MyGUI::IntCoord widgetCoord( + worldX * mGlobalMapRender->getWidth()+6, + worldY * mGlobalMapRender->getHeight()+6, + 12, 12); + + + static int _counter=0; + MyGUI::Button* markerWidget = mGlobalMapImage->createWidget("ButtonImage", + widgetCoord, MyGUI::Align::Default, "Marker" + boost::lexical_cast(_counter)); + markerWidget->setImageResource("DoorMarker"); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + ++_counter; + + markerWidget = mEventBoxGlobal->createWidget("", + widgetCoord, MyGUI::Align::Default); + markerWidget->setNeedMouseFocus (true); + markerWidget->setUserString("ToolTipType", "Layout"); + markerWidget->setUserString("ToolTipLayout", "TextToolTipOneLine"); + markerWidget->setUserString("Caption_TextOneLine", name); + } + + void MapWindow::cellExplored(int x, int y) + { + mGlobalMapRender->exploreCell(x,y); + } + + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + if (_id!=MyGUI::MouseButton::Left) return; + mLastDragPos = MyGUI::IntPoint(_left, _top); + } + + void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) + { + if (_id!=MyGUI::MouseButton::Left) return; + + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; + + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); + } + + void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) + { + mGlobal = !mGlobal; + mGlobalMap->setVisible(mGlobal); + mLocalMap->setVisible(!mGlobal); + + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + + if (mGlobal) + globalMapUpdatePlayer (); + } + + void MapWindow::onPinToggled() + { + MWBase::Environment::get().getWindowManager()->setMinimapVisibility(!mPinned); + } + + void MapWindow::open() + { + mGlobalMap->setCanvasSize (mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + mGlobalMapImage->setSize(mGlobalMapRender->getWidth(), mGlobalMapRender->getHeight()); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + globalMapUpdatePlayer(); + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); + } + + void MapWindow::globalMapUpdatePlayer () + { + Ogre::Vector3 pos = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedPosition (); + Ogre::Quaternion orient = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer().getRefData ().getBaseNode ()->_getDerivedOrientation (); + Ogre::Vector2 dir (orient.yAxis ().x, orient.yAxis().y); + + float worldX, worldY; + mGlobalMapRender->worldPosToImageSpace (pos.x, pos.y, worldX, worldY); + worldX *= mGlobalMapRender->getWidth(); + worldY *= mGlobalMapRender->getHeight(); + + + // for interiors, we have no choice other than using the last position & direction. + /// \todo save this last position in the savegame? + if (MWBase::Environment::get().getWorld ()->isCellExterior ()) + { + mPlayerArrowGlobal->setPosition(MyGUI::IntPoint(worldX - 16, worldY - 16)); + + MyGUI::ISubWidget* main = mPlayerArrowGlobal->getSubWidgetMain(); + MyGUI::RotatingSkin* rotatingSubskin = main->castType(); + rotatingSubskin->setCenter(MyGUI::IntPoint(16,16)); + float angle = std::atan2(dir.x, dir.y); + rotatingSubskin->setAngle(angle); + + // set the view offset so that player is in the center + MyGUI::IntSize viewsize = mGlobalMap->getSize(); + MyGUI::IntPoint viewoffs(0.5*viewsize.width - worldX, 0.5*viewsize.height - worldY); + mGlobalMap->setViewOffset(viewoffs); + } + } + + void MapWindow::notifyPlayerUpdate () + { + globalMapUpdatePlayer (); + } + + void MapWindow::notifyMapChanged () + { + // workaround to prevent the map from drawing on top of the button + MyGUI::IntCoord oldCoord = mButton->getCoord (); + MyGUI::Gui::getInstance().destroyWidget (mButton); + mButton = mMainWidget->createWidget("MW_Button", + oldCoord, MyGUI::Align::Bottom | MyGUI::Align::Right); + mButton->setProperty ("ExpandDirection", "Left"); + + mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); + mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : + "#{sWorld}"); + } - mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); - mButton->setCaptionWithReplacing( mGlobal ? "#{sLocal}" : - "#{sWorld}"); } diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index 8e53380bde..876fb35220 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -5,411 +5,414 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/inputmanager.hpp" -using namespace MWGui; - -MessageBoxManager::MessageBoxManager () +namespace MWGui { - // defines - mMessageBoxSpeed = 0.1; - mInterMessageBoxe = NULL; -} -void MessageBoxManager::onFrame (float frameDuration) -{ - std::vector::iterator it; - for(it = mTimers.begin(); it != mTimers.end();) + MessageBoxManager::MessageBoxManager () { - // 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; - } + // defines + mMessageBoxSpeed = 0.1; + mInterMessageBoxe = NULL; + } - it->current += frameDuration; - if(it->current >= it->max) + void MessageBoxManager::onFrame (float frameDuration) + { + std::vector::iterator it; + for(it = mTimers.begin(); it != mTimers.end();) { - it->messageBox->mMarkedToDelete = true; - - if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one + // if this messagebox is already deleted, remove the timer and move on + if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) { - // collect all with mMarkedToDelete and delete them. - // and place the other messageboxes on the right position - int height = 0; - std::vector::iterator it2 = mMessageBoxes.begin(); - while(it2 != mMessageBoxes.end()) + it = mTimers.erase(it); + continue; + } + + it->current += frameDuration; + if(it->current >= it->max) + { + it->messageBox->mMarkedToDelete = true; + + if(*mMessageBoxes.begin() == it->messageBox) // if this box is the last one { - if((*it2)->mMarkedToDelete) + // collect all with mMarkedToDelete and delete them. + // and place the other messageboxes on the right position + int height = 0; + std::vector::iterator it2 = mMessageBoxes.begin(); + while(it2 != mMessageBoxes.end()) { - delete (*it2); - it2 = mMessageBoxes.erase(it2); - } - else { - (*it2)->update(height); - height += (*it2)->getHeight(); - it2++; + if((*it2)->mMarkedToDelete) + { + delete (*it2); + it2 = mMessageBoxes.erase(it2); + } + else { + (*it2)->update(height); + height += (*it2)->getHeight(); + it2++; + } } } + it = mTimers.erase(it); + } + else + { + it++; + } + } + + if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { + delete mInterMessageBoxe; + mInterMessageBoxe = NULL; + MWBase::Environment::get().getInputManager()->changeInputMode( + MWBase::Environment::get().getWindowManager()->isGuiMode()); + } + } + + void MessageBoxManager::createMessageBox (const std::string& message) + { + MessageBox *box = new MessageBox(*this, message); + + removeMessageBox(message.length()*mMessageBoxSpeed, box); + + mMessageBoxes.push_back(box); + std::vector::iterator it; + + if(mMessageBoxes.size() > 3) { + delete *mMessageBoxes.begin(); + mMessageBoxes.erase(mMessageBoxes.begin()); + } + + int height = 0; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + (*it)->update(height); + height += (*it)->getHeight(); + } + } + + bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) + { + if(mInterMessageBoxe != NULL) { + throw std::runtime_error("There is a message box already"); + } + + mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); + + return true; + } + + bool MessageBoxManager::isInteractiveMessageBox () + { + return mInterMessageBoxe != NULL; + } + + void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) + { + MessageBoxManagerTimer timer; + timer.current = 0; + timer.max = time; + timer.messageBox = msgbox; + + mTimers.insert(mTimers.end(), timer); + } + + bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) + { + std::vector::iterator it; + for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + { + if((*it) == msgbox) + { + delete (*it); + mMessageBoxes.erase(it); + return true; + } + } + return false; + } + + void MessageBoxManager::setMessageBoxSpeed (int speed) + { + mMessageBoxSpeed = speed; + } + + void MessageBoxManager::enterPressed () + { + if(mInterMessageBoxe != NULL) + mInterMessageBoxe->enterPressed(); + } + + int MessageBoxManager::readPressedButton () + { + if(mInterMessageBoxe != NULL) + { + return mInterMessageBoxe->readPressedButton(); + } + return -1; + } + + + + + MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) + : Layout("openmw_messagebox.layout") + , mMessageBoxManager(parMessageBoxManager) + , mMessage(message) + { + // defines + mFixedWidth = 300; + mBottomPadding = 20; + mNextBoxPadding = 20; + mMarkedToDelete = false; + + getWidget(mMessageWidget, "message"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->setCaptionWithReplacing(mMessage); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = 100; // dummy + + MyGUI::IntCoord coord; + coord.left = 10; // dummy + coord.top = 10; // dummy + + mMessageWidget->setSize(size); + + MyGUI::IntSize textSize = mMessageWidget->getTextSize(); + + size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box + + mMainWidget->setSize(size); + size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") + mMessageWidget->setSize(size); + } + + void MessageBox::update (int height) + { + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntCoord coord; + coord.left = (gameWindowSize.width - mFixedWidth)/2; + coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); + + MyGUI::IntSize size; + size.width = mFixedWidth; + size.height = mHeight; + + mMainWidget->setCoord(coord); + mMainWidget->setSize(size); + mMainWidget->setVisible(true); + } + + int MessageBox::getHeight () + { + return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox + } + + + + InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) + : WindowModal("openmw_interactive_messagebox.layout") + , mMessageBoxManager(parMessageBoxManager) + , mButtonPressed(-1) + { + WindowModal::open(); + + int fixedWidth = 500; + int textPadding = 10; // padding between text-widget and main-widget + int textButtonPadding = 20; // padding between the text-widget und the button-widget + int buttonLeftPadding = 10; // padding between the buttons if horizontal + int buttonTopPadding = 5; // ^-- if vertical + int buttonPadding = 5; // padding between button label and button itself + int buttonMainPadding = 10; // padding between buttons and bottom of the main widget + + mMarkedToDelete = false; + + + getWidget(mMessageWidget, "message"); + getWidget(mButtonsWidget, "buttons"); + + mMessageWidget->setOverflowToTheLeft(true); + mMessageWidget->setCaptionWithReplacing(message); + + MyGUI::IntSize textSize = mMessageWidget->getTextSize(); + + MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); + + int biggestButtonWidth = 0; + int buttonWidth = 0; + int buttonsWidth = 0; + int buttonHeight = 0; + MyGUI::IntCoord dummyCoord(0, 0, 0, 0); + + std::vector::const_iterator it; + for(it = buttons.begin(); it != buttons.end(); ++it) + { + MyGUI::Button* button = mButtonsWidget->createWidget( + MyGUI::WidgetStyle::Child, + std::string("MW_Button"), + dummyCoord, + MyGUI::Align::Default); + button->setCaptionWithReplacing(*it); + + button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); + + mButtons.push_back(button); + + buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding; + buttonsWidth += buttonWidth; + buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding; + + if(buttonWidth > biggestButtonWidth) + { + biggestButtonWidth = buttonWidth; + } + } + buttonsWidth += buttonLeftPadding; + + MyGUI::IntSize mainWidgetSize; + if(buttonsWidth < fixedWidth) + { + // on one line + if(textSize.width + 2*textPadding < buttonsWidth) + { + mainWidgetSize.width = buttonsWidth; + } + else + { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonCord.left = left; + buttonCord.top = textSize.height + textButtonPadding; + + buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; + buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + left += buttonSize.width + buttonLeftPadding; } - it = mTimers.erase(it); } else { - it++; + // among each other + if(biggestButtonWidth > textSize.width) { + mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; + } + else { + mainWidgetSize.width = textSize.width + 3*textPadding; + } + mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; + + mMainWidget->setSize(mainWidgetSize); + + MyGUI::IntCoord absCoord; + absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; + absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; + + mMainWidget->setCoord(absCoord); + mMainWidget->setSize(mainWidgetSize); + + + MyGUI::IntCoord messageWidgetCoord; + messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; + messageWidgetCoord.top = textPadding; + mMessageWidget->setCoord(messageWidgetCoord); + + mMessageWidget->setSize(textSize); + + MyGUI::IntCoord buttonCord; + MyGUI::IntSize buttonSize(0, buttonHeight); + + int top = textButtonPadding + buttonTopPadding + textSize.height; + + std::vector::const_iterator button; + for(button = mButtons.begin(); button != mButtons.end(); ++button) + { + buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; + buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; + + buttonCord.top = top; + buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ + + (*button)->setCoord(buttonCord); + (*button)->setSize(buttonSize); + + top += buttonSize.height + 2*buttonTopPadding; + } + } } - if(mInterMessageBoxe != NULL && mInterMessageBoxe->mMarkedToDelete) { - delete mInterMessageBoxe; - mInterMessageBoxe = NULL; - MWBase::Environment::get().getInputManager()->changeInputMode( - MWBase::Environment::get().getWindowManager()->isGuiMode()); - } -} - -void MessageBoxManager::createMessageBox (const std::string& message) -{ - MessageBox *box = new MessageBox(*this, message); - - removeMessageBox(message.length()*mMessageBoxSpeed, box); - - mMessageBoxes.push_back(box); - std::vector::iterator it; - - if(mMessageBoxes.size() > 3) { - delete *mMessageBoxes.begin(); - mMessageBoxes.erase(mMessageBoxes.begin()); - } - - int height = 0; - for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) + void InteractiveMessageBox::enterPressed() { - (*it)->update(height); - height += (*it)->getHeight(); - } -} - -bool MessageBoxManager::createInteractiveMessageBox (const std::string& message, const std::vector& buttons) -{ - if(mInterMessageBoxe != NULL) { - throw std::runtime_error("There is a message box already"); - } - - mInterMessageBoxe = new InteractiveMessageBox(*this, message, buttons); - - return true; -} - -bool MessageBoxManager::isInteractiveMessageBox () -{ - return mInterMessageBoxe != NULL; -} - -void MessageBoxManager::removeMessageBox (float time, MessageBox *msgbox) -{ - MessageBoxManagerTimer timer; - timer.current = 0; - timer.max = time; - timer.messageBox = msgbox; - - mTimers.insert(mTimers.end(), timer); -} - -bool MessageBoxManager::removeMessageBox (MessageBox *msgbox) -{ - std::vector::iterator it; - for(it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it) - { - if((*it) == msgbox) - { - delete (*it); - mMessageBoxes.erase(it); - return true; - } - } - return false; -} - -void MessageBoxManager::setMessageBoxSpeed (int speed) -{ - mMessageBoxSpeed = speed; -} - -void MessageBoxManager::enterPressed () -{ - if(mInterMessageBoxe != NULL) - mInterMessageBoxe->enterPressed(); -} - -int MessageBoxManager::readPressedButton () -{ - if(mInterMessageBoxe != NULL) - { - return mInterMessageBoxe->readPressedButton(); - } - return -1; -} - - - - -MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message) - : Layout("openmw_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mMessage(message) -{ - // defines - mFixedWidth = 300; - mBottomPadding = 20; - mNextBoxPadding = 20; - mMarkedToDelete = false; - - getWidget(mMessageWidget, "message"); - - mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(mMessage); - - MyGUI::IntSize size; - size.width = mFixedWidth; - size.height = 100; // dummy - - MyGUI::IntCoord coord; - coord.left = 10; // dummy - coord.top = 10; // dummy - - mMessageWidget->setSize(size); - - MyGUI::IntSize textSize = mMessageWidget->getTextSize(); - - size.height = mHeight = textSize.height + 20; // this is the padding between the text and the box - - mMainWidget->setSize(size); - size.width -= 15; // this is to center the text (see messagebox.layout, Widget type="Edit" position="-2 -3 0 0") - mMessageWidget->setSize(size); -} - -void MessageBox::update (int height) -{ - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - MyGUI::IntCoord coord; - coord.left = (gameWindowSize.width - mFixedWidth)/2; - coord.top = (gameWindowSize.height - mHeight - height - mBottomPadding); - - MyGUI::IntSize size; - size.width = mFixedWidth; - size.height = mHeight; - - mMainWidget->setCoord(coord); - mMainWidget->setSize(size); - mMainWidget->setVisible(true); -} - -int MessageBox::getHeight () -{ - return mHeight+mNextBoxPadding; // 20 is the padding between this and the next MessageBox -} - - - -InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message, const std::vector& buttons) - : WindowModal("openmw_interactive_messagebox.layout") - , mMessageBoxManager(parMessageBoxManager) - , mButtonPressed(-1) -{ - WindowModal::open(); - - int fixedWidth = 500; - int textPadding = 10; // padding between text-widget and main-widget - int textButtonPadding = 20; // padding between the text-widget und the button-widget - int buttonLeftPadding = 10; // padding between the buttons if horizontal - int buttonTopPadding = 5; // ^-- if vertical - int buttonPadding = 5; // padding between button label and button itself - int buttonMainPadding = 10; // padding between buttons and bottom of the main widget - - mMarkedToDelete = false; - - - getWidget(mMessageWidget, "message"); - getWidget(mButtonsWidget, "buttons"); - - mMessageWidget->setOverflowToTheLeft(true); - mMessageWidget->setCaptionWithReplacing(message); - - MyGUI::IntSize textSize = mMessageWidget->getTextSize(); - - MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize(); - - int biggestButtonWidth = 0; - int buttonWidth = 0; - int buttonsWidth = 0; - int buttonHeight = 0; - MyGUI::IntCoord dummyCoord(0, 0, 0, 0); - - std::vector::const_iterator it; - for(it = buttons.begin(); it != buttons.end(); ++it) - { - MyGUI::Button* button = mButtonsWidget->createWidget( - MyGUI::WidgetStyle::Child, - std::string("MW_Button"), - dummyCoord, - MyGUI::Align::Default); - button->setCaptionWithReplacing(*it); - - button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed); - - mButtons.push_back(button); - - buttonWidth = button->getTextSize().width + 2*buttonPadding + buttonLeftPadding; - buttonsWidth += buttonWidth; - buttonHeight = button->getTextSize().height + 2*buttonPadding + buttonTopPadding; - - if(buttonWidth > biggestButtonWidth) - { - biggestButtonWidth = buttonWidth; - } - } - buttonsWidth += buttonLeftPadding; - - MyGUI::IntSize mainWidgetSize; - if(buttonsWidth < fixedWidth) - { - // on one line - if(textSize.width + 2*textPadding < buttonsWidth) - { - mainWidgetSize.width = buttonsWidth; - } - else - { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + textButtonPadding + buttonHeight + buttonMainPadding; - - MyGUI::IntCoord absCoord; - absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setCoord(absCoord); - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - int left = (mainWidgetSize.width - buttonsWidth)/2 + buttonPadding; + std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonCord.left = left; - buttonCord.top = textSize.height + textButtonPadding; - - buttonSize.width = (*button)->getTextSize().width + 2*buttonPadding; - buttonSize.height = (*button)->getTextSize().height + 2*buttonPadding; - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - left += buttonSize.width + buttonLeftPadding; + if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) + { + buttonActivated(*button); + MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); + break; + } } + } - else + + void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) { - // among each other - if(biggestButtonWidth > textSize.width) { - mainWidgetSize.width = biggestButtonWidth + buttonTopPadding; - } - else { - mainWidgetSize.width = textSize.width + 3*textPadding; - } - mainWidgetSize.height = textSize.height + 2*textPadding + textButtonPadding + buttonHeight * buttons.size() + buttonMainPadding; - - mMainWidget->setSize(mainWidgetSize); - - MyGUI::IntCoord absCoord; - absCoord.left = (gameWindowSize.width - mainWidgetSize.width)/2; - absCoord.top = (gameWindowSize.height - mainWidgetSize.height)/2; - - mMainWidget->setCoord(absCoord); - mMainWidget->setSize(mainWidgetSize); - - - MyGUI::IntCoord messageWidgetCoord; - messageWidgetCoord.left = (mainWidgetSize.width - textSize.width)/2; - messageWidgetCoord.top = textPadding; - mMessageWidget->setCoord(messageWidgetCoord); - - mMessageWidget->setSize(textSize); - - MyGUI::IntCoord buttonCord; - MyGUI::IntSize buttonSize(0, buttonHeight); - - int top = textButtonPadding + buttonTopPadding + textSize.height; + buttonActivated (pressed); + } + void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) + { + mMarkedToDelete = true; + int index = 0; std::vector::const_iterator button; for(button = mButtons.begin(); button != mButtons.end(); ++button) { - buttonSize.width = (*button)->getTextSize().width + buttonPadding*2; - buttonSize.height = (*button)->getTextSize().height + buttonPadding*2; - - buttonCord.top = top; - buttonCord.left = (mainWidgetSize.width - buttonSize.width)/2 - 5; // FIXME: -5 is not so nice :/ - - (*button)->setCoord(buttonCord); - (*button)->setSize(buttonSize); - - top += buttonSize.height + 2*buttonTopPadding; + if(*button == pressed) + { + mButtonPressed = index; + mMessageBoxManager.onButtonPressed(mButtonPressed); + return; + } + index++; } - } -} -void InteractiveMessageBox::enterPressed() -{ - - std::string ok = Misc::StringUtils::lowerCase(MyGUI::LanguageManager::getInstance().replaceTags("#{sOK}")); - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) + int InteractiveMessageBox::readPressedButton () { - if(Misc::StringUtils::lowerCase((*button)->getCaption()) == ok) - { - buttonActivated(*button); - MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); - break; - } + int pressed = mButtonPressed; + mButtonPressed = -1; + return pressed; } } - -void InteractiveMessageBox::mousePressed (MyGUI::Widget* pressed) -{ - buttonActivated (pressed); -} - -void InteractiveMessageBox::buttonActivated (MyGUI::Widget* pressed) -{ - mMarkedToDelete = true; - int index = 0; - std::vector::const_iterator button; - for(button = mButtons.begin(); button != mButtons.end(); ++button) - { - if(*button == pressed) - { - mButtonPressed = index; - mMessageBoxManager.onButtonPressed(mButtonPressed); - return; - } - index++; - } -} - -int InteractiveMessageBox::readPressedButton () -{ - int pressed = mButtonPressed; - mButtonPressed = -1; - return pressed; -} diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index c031ad6b68..0a7374085f 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -10,435 +10,437 @@ #include "tooltips.hpp" -using namespace MWGui; -using namespace Widgets; - namespace { -int wrap(int index, int max) -{ - if (index < 0) - return max - 1; - else if (index >= max) - return 0; - else - return index; -} - -int countParts(const std::string &part, const std::string &race, bool male) -{ - /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs - const MWWorld::Store &store = - MWBase::Environment::get().getWorld()->getStore().get(); - - std::string prefix = - "b_n_" + race + ((male) ? "_m_" : "_f_") + part; - - std::string suffix; - suffix.reserve(prefix.size() + 3); - - int count = -1; - do { - ++count; - suffix = "_" + (boost::format("%02d") % (count + 1)).str(); + int wrap(int index, int max) + { + if (index < 0) + return max - 1; + else if (index >= max) + return 0; + else + return index; } - while (store.search(prefix + suffix) != 0); - if (count == 0 && part == "hair") { - count = -1; + int countParts(const std::string &part, const std::string &race, bool male) + { + /// \todo loop through the whole store for appropriate bodyparts instead of looking for fixed IDs + const MWWorld::Store &store = + MWBase::Environment::get().getWorld()->getStore().get(); + + std::string prefix = + "b_n_" + race + ((male) ? "_m_" : "_f_") + part; + + std::string suffix; + suffix.reserve(prefix.size() + 3); + + int count = -1; do { ++count; - suffix = (boost::format("%02d") % (count + 1)).str(); + suffix = "_" + (boost::format("%02d") % (count + 1)).str(); } while (store.search(prefix + suffix) != 0); + + if (count == 0 && part == "hair") { + count = -1; + do { + ++count; + suffix = (boost::format("%02d") % (count + 1)).str(); + } + while (store.search(prefix + suffix) != 0); + } + return count; } - return count; -} } -RaceDialog::RaceDialog() - : WindowModal("openmw_chargen_race.layout") - , mGenderIndex(0) - , mFaceIndex(0) - , mHairIndex(0) - , mFaceCount(10) - , mHairCount(14) - , mCurrentAngle(0) +namespace MWGui { - // Centre dialog - center(); - setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); - getWidget(mPreviewImage, "PreviewImage"); - - getWidget(mHeadRotate, "HeadRotate"); - mHeadRotate->setScrollRange(50); - mHeadRotate->setScrollPosition(25); - mHeadRotate->setScrollViewPage(10); - mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); - - // Set up next/previous buttons - MyGUI::Button *prevButton, *nextButton; - - setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); - getWidget(prevButton, "PrevGenderButton"); - getWidget(nextButton, "NextGenderButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); - - setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); - getWidget(prevButton, "PrevFaceButton"); - getWidget(nextButton, "NextFaceButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); - - setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); - getWidget(prevButton, "PrevHairButton"); - getWidget(nextButton, "NextHairButton"); - prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); - nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); - - setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); - getWidget(mRaceList, "RaceList"); - mRaceList->setScrollVisible(true); - mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); - - setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); - getWidget(mSkillList, "SkillList"); - setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); - getWidget(mSpellPowerList, "SpellPowerList"); - - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); - - updateRaces(); - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -void RaceDialog::open() -{ - WindowModal::open(); - - updateRaces(); - updateSkills(); - updateSpellPowers(); - - mPreview = new MWRender::RaceSelectionPreview(); - mPreview->setup(); - mPreview->update (0); - - const ESM::NPC proto = mPreview->getPrototype(); - setRaceId(proto.mRace); - recountParts(); - - std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); - mFaceIndex = boost::lexical_cast(index) - 1; - - index = proto.mHair.substr(proto.mHair.size() - 2, 2); - mHairIndex = boost::lexical_cast(index) - 1; - - mPreviewImage->setImageTexture ("CharacterHeadPreview"); -} - - -void RaceDialog::setRaceId(const std::string &raceId) -{ - mCurrentRaceId = raceId; - mRaceList->setIndexSelected(MyGUI::ITEM_NONE); - size_t count = mRaceList->getItemCount(); - for (size_t i = 0; i < count; ++i) + RaceDialog::RaceDialog() + : WindowModal("openmw_chargen_race.layout") + , mGenderIndex(0) + , mFaceIndex(0) + , mHairIndex(0) + , mFaceCount(10) + , mHairCount(14) + , mCurrentAngle(0) { - if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) + // Centre dialog + center(); + + setText("AppearanceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu1", "Appearance")); + getWidget(mPreviewImage, "PreviewImage"); + + getWidget(mHeadRotate, "HeadRotate"); + mHeadRotate->setScrollRange(50); + mHeadRotate->setScrollPosition(25); + mHeadRotate->setScrollViewPage(10); + mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); + + // Set up next/previous buttons + MyGUI::Button *prevButton, *nextButton; + + setText("GenderChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu2", "Change Sex")); + getWidget(prevButton, "PrevGenderButton"); + getWidget(nextButton, "NextGenderButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousGender); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextGender); + + setText("FaceChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu3", "Change Face")); + getWidget(prevButton, "PrevFaceButton"); + getWidget(nextButton, "NextFaceButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousFace); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextFace); + + setText("HairChoiceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu4", "Change Hair")); + getWidget(prevButton, "PrevHairButton"); + getWidget(nextButton, "NextHairButton"); + prevButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectPreviousHair); + nextButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onSelectNextHair); + + setText("RaceT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu5", "Race")); + getWidget(mRaceList, "RaceList"); + mRaceList->setScrollVisible(true); + mRaceList->eventListSelectAccept += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListMouseItemActivate += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + mRaceList->eventListChangePosition += MyGUI::newDelegate(this, &RaceDialog::onSelectRace); + + setText("SkillsT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sBonusSkillTitle", "Skill Bonus")); + getWidget(mSkillList, "SkillList"); + setText("SpellPowerT", MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); + getWidget(mSpellPowerList, "SpellPowerList"); + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + + updateRaces(); + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void RaceDialog::open() + { + WindowModal::open(); + + updateRaces(); + updateSkills(); + updateSpellPowers(); + + mPreview = new MWRender::RaceSelectionPreview(); + mPreview->setup(); + mPreview->update (0); + + const ESM::NPC proto = mPreview->getPrototype(); + setRaceId(proto.mRace); + recountParts(); + + std::string index = proto.mHead.substr(proto.mHead.size() - 2, 2); + mFaceIndex = boost::lexical_cast(index) - 1; + + index = proto.mHair.substr(proto.mHair.size() - 2, 2); + mHairIndex = boost::lexical_cast(index) - 1; + + mPreviewImage->setImageTexture ("CharacterHeadPreview"); + } + + + void RaceDialog::setRaceId(const std::string &raceId) + { + mCurrentRaceId = raceId; + mRaceList->setIndexSelected(MyGUI::ITEM_NONE); + size_t count = mRaceList->getItemCount(); + for (size_t i = 0; i < count; ++i) { - mRaceList->setIndexSelected(i); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - break; + if (boost::iequals(*mRaceList->getItemDataAt(i), raceId)) + { + mRaceList->setIndexSelected(i); + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + break; + } + } + + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::close() + { + delete mPreview; + mPreview = 0; + } + + // widget controls + + void RaceDialog::onOkClicked(MyGUI::Widget* _sender) + { + if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE) + return; + eventDone(this); + } + + void RaceDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) + { + float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; + float diff = angle - mCurrentAngle; + mPreview->update (diff); + mCurrentAngle += diff; + } + + void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) + { + mGenderIndex = wrap(mGenderIndex - 1, 2); + + recountParts(); + updatePreview(); + } + + void RaceDialog::onSelectNextGender(MyGUI::Widget*) + { + mGenderIndex = wrap(mGenderIndex + 1, 2); + + recountParts(); + updatePreview(); + } + + void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) + { + do + mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); + while (!isFacePlayable()); + updatePreview(); + } + + void RaceDialog::onSelectNextFace(MyGUI::Widget*) + { + do + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + while (!isFacePlayable()); + updatePreview(); + } + + void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) + { + do + mHairIndex = wrap(mHairIndex - 1, mHairCount); + while (!isHairPlayable()); + updatePreview(); + } + + void RaceDialog::onSelectNextHair(MyGUI::Widget*) + { + do + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isHairPlayable()); + updatePreview(); + } + + bool RaceDialog::isFacePlayable() + { + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(prefix + "head_" + headIndex) == 0) + return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + } + + bool RaceDialog::isHairPlayable() + { + std::string prefix = + "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); + + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + if (parts.search(prefix + "hair_" + hairIndex) == 0) + return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + else + return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); + } + + void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) + { + if (_index == MyGUI::ITEM_NONE) + return; + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + const std::string *raceId = mRaceList->getItemDataAt(_index); + if (boost::iequals(mCurrentRaceId, *raceId)) + return; + + mCurrentRaceId = *raceId; + + recountParts(); + + updatePreview(); + updateSkills(); + updateSpellPowers(); + } + + void RaceDialog::recountParts() + { + mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); + mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); + + mFaceIndex = 0; + mHairIndex = 0; + + while (!isHairPlayable()) + mHairIndex = wrap(mHairIndex + 1, mHairCount); + while (!isFacePlayable()) + mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); + } + + // update widget content + + void RaceDialog::updatePreview() + { + ESM::NPC record = mPreview->getPrototype(); + record.mRace = mCurrentRaceId; + record.setIsMale(mGenderIndex == 0); + + std::string prefix = + "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); + + std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); + std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); + + record.mHead = prefix + "head_" + headIndex; + record.mHair = prefix + "hair_" + hairIndex; + + const MWWorld::Store &parts = + MWBase::Environment::get().getWorld()->getStore().get(); + + if (parts.search(record.mHair) == 0) { + record.mHair = prefix + "hair" + hairIndex; + } + mPreview->setPrototype(record); + } + + void RaceDialog::updateRaces() + { + mRaceList->removeAllItems(); + + const MWWorld::Store &races = + MWBase::Environment::get().getWorld()->getStore().get(); + + + int index = 0; + MWWorld::Store::iterator it = races.begin(); + for (; it != races.end(); ++it) + { + bool playable = it->mData.mFlags & ESM::Race::Playable; + if (!playable) // Only display playable races + continue; + + mRaceList->addItem(it->mName, it->mId); + if (boost::iequals(it->mId, mCurrentRaceId)) + mRaceList->setIndexSelected(index); + ++index; } } - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::close() -{ - delete mPreview; - mPreview = 0; -} - -// widget controls - -void RaceDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if(mRaceList->getIndexSelected() == MyGUI::ITEM_NONE) - return; - eventDone(this); -} - -void RaceDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void RaceDialog::onHeadRotate(MyGUI::ScrollBar*, size_t _position) -{ - float angle = (float(_position) / 49.f - 0.5) * 3.14 * 2; - float diff = angle - mCurrentAngle; - mPreview->update (diff); - mCurrentAngle += diff; -} - -void RaceDialog::onSelectPreviousGender(MyGUI::Widget*) -{ - mGenderIndex = wrap(mGenderIndex - 1, 2); - - recountParts(); - updatePreview(); -} - -void RaceDialog::onSelectNextGender(MyGUI::Widget*) -{ - mGenderIndex = wrap(mGenderIndex + 1, 2); - - recountParts(); - updatePreview(); -} - -void RaceDialog::onSelectPreviousFace(MyGUI::Widget*) -{ - do - mFaceIndex = wrap(mFaceIndex - 1, mFaceCount); - while (!isFacePlayable()); - updatePreview(); -} - -void RaceDialog::onSelectNextFace(MyGUI::Widget*) -{ - do - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); - while (!isFacePlayable()); - updatePreview(); -} - -void RaceDialog::onSelectPreviousHair(MyGUI::Widget*) -{ - do - mHairIndex = wrap(mHairIndex - 1, mHairCount); - while (!isHairPlayable()); - updatePreview(); -} - -void RaceDialog::onSelectNextHair(MyGUI::Widget*) -{ - do - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isHairPlayable()); - updatePreview(); -} - -bool RaceDialog::isFacePlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(prefix + "head_" + headIndex) == 0) - return !(parts.find(prefix + "head" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "head_" + headIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -bool RaceDialog::isHairPlayable() -{ - std::string prefix = - "b_n_" + mCurrentRaceId + ((mGenderIndex == 0) ? "_m_" : "_f_"); - - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - if (parts.search(prefix + "hair_" + hairIndex) == 0) - return !(parts.find(prefix + "hair" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); - else - return !(parts.find(prefix + "hair_" + hairIndex)->mData.mFlags & ESM::BodyPart::BPF_NotPlayable); -} - -void RaceDialog::onSelectRace(MyGUI::ListBox* _sender, size_t _index) -{ - if (_index == MyGUI::ITEM_NONE) - return; - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - const std::string *raceId = mRaceList->getItemDataAt(_index); - if (boost::iequals(mCurrentRaceId, *raceId)) - return; - - mCurrentRaceId = *raceId; - - recountParts(); - - updatePreview(); - updateSkills(); - updateSpellPowers(); -} - -void RaceDialog::recountParts() -{ - mFaceCount = countParts("head", mCurrentRaceId, mGenderIndex == 0); - mHairCount = countParts("hair", mCurrentRaceId, mGenderIndex == 0); - - mFaceIndex = 0; - mHairIndex = 0; - - while (!isHairPlayable()) - mHairIndex = wrap(mHairIndex + 1, mHairCount); - while (!isFacePlayable()) - mFaceIndex = wrap(mFaceIndex + 1, mFaceCount); -} - -// update widget content - -void RaceDialog::updatePreview() -{ - ESM::NPC record = mPreview->getPrototype(); - record.mRace = mCurrentRaceId; - record.setIsMale(mGenderIndex == 0); - - std::string prefix = - "b_n_" + mCurrentRaceId + ((record.isMale()) ? "_m_" : "_f_"); - - std::string headIndex = (boost::format("%02d") % (mFaceIndex + 1)).str(); - std::string hairIndex = (boost::format("%02d") % (mHairIndex + 1)).str(); - - record.mHead = prefix + "head_" + headIndex; - record.mHair = prefix + "hair_" + hairIndex; - - const MWWorld::Store &parts = - MWBase::Environment::get().getWorld()->getStore().get(); - - if (parts.search(record.mHair) == 0) { - record.mHair = prefix + "hair" + hairIndex; - } - mPreview->setPrototype(record); -} - -void RaceDialog::updateRaces() -{ - mRaceList->removeAllItems(); - - const MWWorld::Store &races = - MWBase::Environment::get().getWorld()->getStore().get(); - - - int index = 0; - MWWorld::Store::iterator it = races.begin(); - for (; it != races.end(); ++it) + void RaceDialog::updateSkills() { - bool playable = it->mData.mFlags & ESM::Race::Playable; - if (!playable) // Only display playable races - continue; + for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillItems.clear(); - mRaceList->addItem(it->mName, it->mId); - if (boost::iequals(it->mId, mCurrentRaceId)) - mRaceList->setIndexSelected(index); - ++index; - } -} - -void RaceDialog::updateSkills() -{ - for (std::vector::iterator it = mSkillItems.begin(); it != mSkillItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillItems.clear(); - - if (mCurrentRaceId.empty()) - return; - - MWSkillPtr skillWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(mCurrentRaceId); - int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? - for (int i = 0; i < count; ++i) - { - int skillId = race->mData.mBonus[i].mSkill; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - - skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, - std::string("Skill") + boost::lexical_cast(i)); - skillWidget->setSkillNumber(skillId); - skillWidget->setSkillValue(MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); - ToolTips::createSkillToolTip(skillWidget, skillId); - - - mSkillItems.push_back(skillWidget); - - coord1.top += lineHeight; - } -} - -void RaceDialog::updateSpellPowers() -{ - for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSpellPowerItems.clear(); - - if (mCurrentRaceId.empty()) - return; - - MWSpellPtr spellPowerWidget; - const int lineHeight = 18; - MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); - - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - const ESM::Race *race = store.get().find(mCurrentRaceId); - - std::vector::const_iterator it = race->mPowers.mList.begin(); - std::vector::const_iterator end = race->mPowers.mList.end(); - for (int i = 0; it != end; ++it) - { - const std::string &spellpower = *it; - spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); - spellPowerWidget->setSpellId(spellpower); - spellPowerWidget->setUserString("ToolTipType", "Spell"); - spellPowerWidget->setUserString("Spell", spellpower); - - mSpellPowerItems.push_back(spellPowerWidget); - - coord.top += lineHeight; - ++i; + if (mCurrentRaceId.empty()) + return; + + Widgets::MWSkillPtr skillWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord1(0, 0, mSkillList->getWidth(), 18); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); + int count = sizeof(race->mData.mBonus)/sizeof(race->mData.mBonus[0]); // TODO: Find a portable macro for this ARRAYSIZE? + for (int i = 0; i < count; ++i) + { + int skillId = race->mData.mBonus[i].mSkill; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + + skillWidget = mSkillList->createWidget("MW_StatNameValue", coord1, MyGUI::Align::Default, + std::string("Skill") + boost::lexical_cast(i)); + skillWidget->setSkillNumber(skillId); + skillWidget->setSkillValue(Widgets::MWSkill::SkillValue(race->mData.mBonus[i].mBonus)); + ToolTips::createSkillToolTip(skillWidget, skillId); + + + mSkillItems.push_back(skillWidget); + + coord1.top += lineHeight; + } } + + void RaceDialog::updateSpellPowers() + { + for (std::vector::iterator it = mSpellPowerItems.begin(); it != mSpellPowerItems.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSpellPowerItems.clear(); + + if (mCurrentRaceId.empty()) + return; + + Widgets::MWSpellPtr spellPowerWidget; + const int lineHeight = 18; + MyGUI::IntCoord coord(0, 0, mSpellPowerList->getWidth(), 18); + + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + const ESM::Race *race = store.get().find(mCurrentRaceId); + + std::vector::const_iterator it = race->mPowers.mList.begin(); + std::vector::const_iterator end = race->mPowers.mList.end(); + for (int i = 0; it != end; ++it) + { + const std::string &spellpower = *it; + spellPowerWidget = mSpellPowerList->createWidget("MW_StatName", coord, MyGUI::Align::Default, std::string("SpellPower") + boost::lexical_cast(i)); + spellPowerWidget->setSpellId(spellpower); + spellPowerWidget->setUserString("ToolTipType", "Spell"); + spellPowerWidget->setUserString("Spell", spellpower); + + mSpellPowerItems.push_back(spellPowerWidget); + + coord.top += lineHeight; + ++i; + } + } + } diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 31f5d737b9..824929b67e 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -11,357 +11,359 @@ #undef min #undef max -using namespace MWGui; -using namespace Widgets; - -const int ReviewDialog::sLineHeight = 18; - -ReviewDialog::ReviewDialog() - : WindowModal("openmw_chargen_review.layout") - , mLastPos(0) +namespace MWGui { - // Centre dialog - center(); - // Setup static stats - MyGUI::Button* button; - getWidget(mNameWidget, "NameText"); - getWidget(button, "NameButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; + const int ReviewDialog::sLineHeight = 18; - getWidget(mRaceWidget, "RaceText"); - getWidget(button, "RaceButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - - getWidget(mClassWidget, "ClassText"); - getWidget(button, "ClassButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - - getWidget(mBirthSignWidget, "SignText"); - getWidget(button, "SignButton"); - adjustButtonSize(button); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; - - // Setup dynamic stats - getWidget(mHealth, "Health"); - mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); - mHealth->setValue(45, 45); - - getWidget(mMagicka, "Magicka"); - mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); - mMagicka->setValue(50, 50); - - getWidget(mFatigue, "Fatigue"); - mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); - mFatigue->setValue(160, 160); - - // Setup attributes - - MWAttributePtr attribute; - for (int idx = 0; idx < ESM::Attribute::Length; ++idx) + ReviewDialog::ReviewDialog() + : WindowModal("openmw_chargen_review.layout") + , mLastPos(0) { - getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); - mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); - attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); - attribute->setAttributeValue(MWAttribute::AttributeValue(0, 0)); - } + // Centre dialog + center(); - // Setup skills - getWidget(mSkillView, "SkillView"); - mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + // Setup static stats + MyGUI::Button* button; + getWidget(mNameWidget, "NameText"); + getWidget(button, "NameButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); - } + getWidget(mRaceWidget, "RaceText"); + getWidget(button, "RaceButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + getWidget(mClassWidget, "ClassText"); + getWidget(button, "ClassButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); -} + getWidget(mBirthSignWidget, "SignText"); + getWidget(button, "SignButton"); + adjustButtonSize(button); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; -void ReviewDialog::open() -{ - WindowModal::open(); - updateSkillArea(); -} + // Setup dynamic stats + getWidget(mHealth, "Health"); + mHealth->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sHealth", "")); + mHealth->setValue(45, 45); -void ReviewDialog::setPlayerName(const std::string &name) -{ - mNameWidget->setCaption(name); -} + getWidget(mMagicka, "Magicka"); + mMagicka->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sMagic", "")); + mMagicka->setValue(50, 50); -void ReviewDialog::setRace(const std::string &raceId) -{ - mRaceId = raceId; + getWidget(mFatigue, "Fatigue"); + mFatigue->setTitle(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFatigue", "")); + mFatigue->setValue(160, 160); - const ESM::Race *race = - MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); - if (race) - { - ToolTips::createRaceToolTip(mRaceWidget, race); - mRaceWidget->setCaption(race->mName); - } -} + // Setup attributes -void ReviewDialog::setClass(const ESM::Class& class_) -{ - mKlass = class_; - mClassWidget->setCaption(mKlass.mName); - ToolTips::createClassToolTip(mClassWidget, mKlass); -} - -void ReviewDialog::setBirthSign(const std::string& signId) -{ - mBirthSignId = signId; - - const ESM::BirthSign *sign = - MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); - if (sign) - { - mBirthSignWidget->setCaption(sign->mName); - ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); - } -} - -void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) -{ - mHealth->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); -} - -void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) -{ - mMagicka->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); -} - -void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) -{ - mFatigue->setValue(value.getCurrent(), value.getModified()); - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); -} - -void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) -{ - std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); - if (attr == mAttributeWidgets.end()) - return; - - attr->second->setAttributeValue(value); -} - -void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) -{ - mSkillValues[skillId] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } - -} - -void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); - } - - updateSkillArea(); -} - -void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); - separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->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); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -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; - - skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); - } - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) - { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); - - for (int i=0; i<2; ++i) + Widgets::MWAttributePtr attribute; + for (int idx = 0; idx < ESM::Attribute::Length; ++idx) { - ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); + getWidget(attribute, std::string("Attribute") + boost::lexical_cast(idx)); + mAttributeWidgets.insert(std::make_pair(static_cast(ESM::Attribute::sAttributeIds[idx]), attribute)); + attribute->setAttributeId(ESM::Attribute::sAttributeIds[idx]); + attribute->setAttributeValue(Widgets::MWAttribute::AttributeValue(0, 0)); } - mSkillWidgetMap[skillId] = widget; - } -} + // Setup skills + getWidget(mSkillView, "SkillView"); + mSkillView->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); -void ReviewDialog::updateSkillArea() -{ - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + for (int i = 0; i < ESM::Skill::Length; ++i) + { + mSkillValues.insert(std::make_pair(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::make_pair(i, static_cast (0))); + } + + MyGUI::Button* backButton; + getWidget(backButton, "BackButton"); + backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onOkClicked); + } + + void ReviewDialog::open() { - MyGUI::Gui::getInstance().destroyWidget(*it); + WindowModal::open(); + updateSkillArea(); } - mSkillWidgets.clear(); - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + void ReviewDialog::setPlayerName(const std::string &name) + { + mNameWidget->setCaption(name); + } - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + void ReviewDialog::setRace(const std::string &raceId) + { + mRaceId = raceId; - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().search(mRaceId); + if (race) + { + ToolTips::createRaceToolTip(mRaceWidget, race); + mRaceWidget->setCaption(race->mName); + } + } - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + void ReviewDialog::setClass(const ESM::Class& class_) + { + mKlass = class_; + mClassWidget->setCaption(mKlass.mName); + ToolTips::createClassToolTip(mClassWidget, mKlass); + } - mClientHeight = coord1.top; + void ReviewDialog::setBirthSign(const std::string& signId) + { + mBirthSignId = signId; + + const ESM::BirthSign *sign = + MWBase::Environment::get().getWorld()->getStore().get().search(mBirthSignId); + if (sign) + { + mBirthSignWidget->setCaption(sign->mName); + ToolTips::createBirthsignToolTip(mBirthSignWidget, mBirthSignId); + } + } + + void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) + { + mHealth->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mHealth->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + + void ReviewDialog::setMagicka(const MWMechanics::DynamicStat& value) + { + mMagicka->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mMagicka->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + + void ReviewDialog::setFatigue(const MWMechanics::DynamicStat& value) + { + mFatigue->setValue(value.getCurrent(), value.getModified()); + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + mFatigue->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } + + void ReviewDialog::setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value) + { + std::map::iterator attr = mAttributeWidgets.find(static_cast(attributeId)); + if (attr == mAttributeWidgets.end()) + return; + + attr->second->setAttributeValue(value); + } + + void ReviewDialog::setSkillValue(ESM::Skill::SkillEnum skillId, const MWMechanics::Stat& value) + { + mSkillValues[skillId] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[skillId]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + + widget->setCaption(text); + widget->_setWidgetState(state); + } + + } + + void ReviewDialog::configureSkills(const std::vector& major, const std::vector& minor) + { + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } + + updateSkillArea(); + } + + void ReviewDialog::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::ImageBox* separator = mSkillView->createWidget("MW_HLine", MyGUI::IntCoord(10, coord1.top, coord1.width + coord2.width - 4, 18), MyGUI::Align::Default); + separator->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); + } + + void ReviewDialog::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* groupWidget = mSkillView->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); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + 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; + + skillNameWidget = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Top | MyGUI::Align::Right); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; + } + + void ReviewDialog::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &ReviewDialog::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + void ReviewDialog::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + ToolTips::createSkillToolTip(mSkillWidgets[mSkillWidgets.size()-1-i], skillId); + } + + mSkillWidgetMap[skillId] = widget; + } + } + + void ReviewDialog::updateSkillArea() + { + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); + } + + // widget controls + + void ReviewDialog::onOkClicked(MyGUI::Widget* _sender) + { + eventDone(this); + } + + void ReviewDialog::onBackClicked(MyGUI::Widget* _sender) + { + eventBack(); + } + + void ReviewDialog::onNameClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(NAME_DIALOG); + } + + void ReviewDialog::onRaceClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(RACE_DIALOG); + } + + void ReviewDialog::onClassClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(CLASS_DIALOG); + } + + void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) + { + eventActivateDialog(BIRTHSIGN_DIALOG); + } + + void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + } - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -// widget controls - -void ReviewDialog::onOkClicked(MyGUI::Widget* _sender) -{ - eventDone(this); -} - -void ReviewDialog::onBackClicked(MyGUI::Widget* _sender) -{ - eventBack(); -} - -void ReviewDialog::onNameClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(NAME_DIALOG); -} - -void ReviewDialog::onRaceClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(RACE_DIALOG); -} - -void ReviewDialog::onClassClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(CLASS_DIALOG); -} - -void ReviewDialog::onBirthSignClicked(MyGUI::Widget* _sender) -{ - eventActivateDialog(BIRTHSIGN_DIALOG); -} - -void ReviewDialog::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); } diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 1935f7a9b6..95bf17635f 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -10,71 +10,73 @@ #include "formatting.hpp" -using namespace MWGui; - -ScrollWindow::ScrollWindow () - : WindowBase("openmw_scroll.layout") - , mTakeButtonShow(true) - , mTakeButtonAllowed(true) +namespace MWGui { - getWidget(mTextView, "TextView"); - getWidget(mCloseButton, "CloseButton"); - mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); + ScrollWindow::ScrollWindow () + : WindowBase("openmw_scroll.layout") + , mTakeButtonShow(true) + , mTakeButtonAllowed(true) + { + getWidget(mTextView, "TextView"); - getWidget(mTakeButton, "TakeButton"); - mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + getWidget(mCloseButton, "CloseButton"); + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onCloseButtonClicked); - center(); -} - -void ScrollWindow::open (MWWorld::Ptr scroll) -{ - // no 3d sounds because the object could be in a container. - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - mScroll = scroll; - - MWWorld::LiveCellRef *ref = mScroll.get(); - - BookTextParser parser; - MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); - - if (size.height > mTextView->getSize().height) - mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); - else - mTextView->setCanvasSize(410, mTextView->getSize().height); - - mTextView->setViewOffset(MyGUI::IntPoint(0,0)); - - setTakeButtonShow(true); -} - -void ScrollWindow::setTakeButtonShow(bool show) -{ - mTakeButtonShow = show; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void ScrollWindow::setInventoryAllowed(bool allowed) -{ - mTakeButtonAllowed = allowed; - mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); -} - -void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); -} - -void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) -{ - MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); - - MWWorld::ActionTake take(mScroll); - take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - - MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + getWidget(mTakeButton, "TakeButton"); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ScrollWindow::onTakeButtonClicked); + + center(); + } + + void ScrollWindow::open (MWWorld::Ptr scroll) + { + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + mScroll = scroll; + + MWWorld::LiveCellRef *ref = mScroll.get(); + + BookTextParser parser; + MyGUI::IntSize size = parser.parse(ref->mBase->mText, mTextView, 390); + + if (size.height > mTextView->getSize().height) + mTextView->setCanvasSize(MyGUI::IntSize(410, size.height)); + else + mTextView->setCanvasSize(410, mTextView->getSize().height); + + mTextView->setViewOffset(MyGUI::IntPoint(0,0)); + + setTakeButtonShow(true); + } + + void ScrollWindow::setTakeButtonShow(bool show) + { + mTakeButtonShow = show; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void ScrollWindow::setInventoryAllowed(bool allowed) + { + mTakeButtonAllowed = allowed; + mTakeButton->setVisible(mTakeButtonShow && mTakeButtonAllowed); + } + + void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } + + void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) + { + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWBase::SoundManager::Play_NoTrack); + + MWWorld::ActionTake take(mScroll); + take.execute (MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + + MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Scroll); + } } diff --git a/apps/openmw/mwgui/statswindow.cpp b/apps/openmw/mwgui/statswindow.cpp index 3439ff31ce..1134767f14 100644 --- a/apps/openmw/mwgui/statswindow.cpp +++ b/apps/openmw/mwgui/statswindow.cpp @@ -13,562 +13,565 @@ #include "tooltips.hpp" -using namespace MWGui; -const int StatsWindow::sLineHeight = 18; - -StatsWindow::StatsWindow () - : WindowPinnableBase("openmw_stats_window.layout") - , mSkillView(NULL) - , mClientHeight(0) - , mMajorSkills() - , mMinorSkills() - , mMiscSkills() - , mSkillValues() - , mSkillWidgetMap() - , mFactionWidgetMap() - , mFactions() - , mBirthSignId() - , mReputation(0) - , mBounty(0) - , mSkillWidgets() - , mChanged(true) +namespace MWGui { - setCoord(0,0,498, 342); - const char *names[][2] = + const int StatsWindow::sLineHeight = 18; + + StatsWindow::StatsWindow () + : WindowPinnableBase("openmw_stats_window.layout") + , mSkillView(NULL) + , mClientHeight(0) + , mMajorSkills() + , mMinorSkills() + , mMiscSkills() + , mSkillValues() + , mSkillWidgetMap() + , mFactionWidgetMap() + , mFactions() + , mBirthSignId() + , mReputation(0) + , mBounty(0) + , mSkillWidgets() + , mChanged(true) { - { "Attrib1", "sAttributeStrength" }, - { "Attrib2", "sAttributeIntelligence" }, - { "Attrib3", "sAttributeWillpower" }, - { "Attrib4", "sAttributeAgility" }, - { "Attrib5", "sAttributeSpeed" }, - { "Attrib6", "sAttributeEndurance" }, - { "Attrib7", "sAttributePersonality" }, - { "Attrib8", "sAttributeLuck" }, - { 0, 0 } - }; + setCoord(0,0,498, 342); - const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); - for (int i=0; names[i][0]; ++i) - { - setText (names[i][0], store.get().find (names[i][1])->getString()); - } - - getWidget(mSkillView, "SkillView"); - getWidget(mLeftPane, "LeftPane"); - getWidget(mRightPane, "RightPane"); - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); - mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); - } - - MyGUI::WindowPtr t = static_cast(mMainWidget); - t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); -} - -void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) -{ - if (mSkillView->getViewOffset().top + _rel*0.3 > 0) - mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); - else - mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); -} - -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) ); - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) -{ - MyGUI::ProgressPtr pt; - getWidget(pt, name); - pt->setProgressRange(max); - pt->setProgressPosition(val); - - std::stringstream out; - out << val << "/" << max; - setText(tname, out.str().c_str()); -} - -void StatsWindow::setPlayerName(const std::string& playerName) -{ - static_cast(mMainWidget)->setCaption(playerName); - adjustWindowCaption(); -} - -void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; - - for (int i=0; ids[i]; ++i) - if (ids[i]==id) + const char *names[][2] = { - std::ostringstream valueString; - valueString << value.getModified(); - setText (id, valueString.str()); + { "Attrib1", "sAttributeStrength" }, + { "Attrib2", "sAttributeIntelligence" }, + { "Attrib3", "sAttributeWillpower" }, + { "Attrib4", "sAttributeAgility" }, + { "Attrib5", "sAttributeSpeed" }, + { "Attrib6", "sAttributeEndurance" }, + { "Attrib7", "sAttributePersonality" }, + { "Attrib8", "sAttributeLuck" }, + { 0, 0 } + }; - MyGUI::TextBox* box; - getWidget(box, id); - - if (value.getModified()>value.getBase()) - box->_setWidgetState("increased"); - else if (value.getModified()_setWidgetState("decreased"); - else - box->_setWidgetState("normal"); - - break; + const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); + for (int i=0; names[i][0]; ++i) + { + setText (names[i][0], store.get().find (names[i][1])->getString()); } -} -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - static const char *ids[] = - { - "HBar", "MBar", "FBar", - 0 - }; + getWidget(mSkillView, "SkillView"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); - for (int i=0; ids[i]; ++i) - { - if (ids[i]==id) + for (int i = 0; i < ESM::Skill::Length; ++i) { - std::string id (ids[i]); - setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); + mSkillValues.insert(std::pair >(i, MWMechanics::Stat())); + mSkillWidgetMap.insert(std::pair(i, (MyGUI::TextBox*)NULL)); + } - // health, magicka, fatigue tooltip - MyGUI::Widget* w; - std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); - if (i==0) + MyGUI::WindowPtr t = static_cast(mMainWidget); + t->eventWindowChangeCoord += MyGUI::newDelegate(this, &StatsWindow::onWindowResize); + } + + void StatsWindow::onMouseWheel(MyGUI::Widget* _sender, int _rel) + { + if (mSkillView->getViewOffset().top + _rel*0.3 > 0) + mSkillView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mSkillView->setViewOffset(MyGUI::IntPoint(0, mSkillView->getViewOffset().top + _rel*0.3)); + } + + 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) ); + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); + } + + void StatsWindow::setBar(const std::string& name, const std::string& tname, int val, int max) + { + MyGUI::ProgressPtr pt; + getWidget(pt, name); + pt->setProgressRange(max); + pt->setProgressPosition(val); + + std::stringstream out; + out << val << "/" << max; + setText(tname, out.str().c_str()); + } + + void StatsWindow::setPlayerName(const std::string& playerName) + { + static_cast(mMainWidget)->setCaption(playerName); + adjustWindowCaption(); + } + + void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& value) + { + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8", + 0 + }; + + for (int i=0; ids[i]; ++i) + if (ids[i]==id) { - getWidget(w, "Health"); - w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + std::ostringstream valueString; + valueString << value.getModified(); + setText (id, valueString.str()); + + MyGUI::TextBox* box; + getWidget(box, id); + + if (value.getModified()>value.getBase()) + box->_setWidgetState("increased"); + else if (value.getModified()_setWidgetState("decreased"); + else + box->_setWidgetState("normal"); + + break; } - else if (i==1) + } + + void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + static const char *ids[] = + { + "HBar", "MBar", "FBar", + 0 + }; + + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) { - getWidget(w, "Magicka"); - w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); - } - else if (i==2) - { - getWidget(w, "Fatigue"); - w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + std::string id (ids[i]); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(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) -{ - if (id=="name") - setPlayerName (value); - else if (id=="race") - setText ("RaceText", value); - else if (id=="class") - setText ("ClassText", value); -} - -void StatsWindow::setValue (const std::string& id, int value) -{ - if (id=="level") + void StatsWindow::setValue (const std::string& id, const std::string& value) { - std::ostringstream text; - text << value; - setText("LevelText", text.str()); - } -} - -void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) -{ - mSkillValues[parSkill] = value; - MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; - if (widget) - { - float modified = value.getModified(), base = value.getBase(); - std::string text = boost::lexical_cast(std::floor(modified)); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - - widget->setCaption(text); - widget->_setWidgetState(state); - } -} - -void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) -{ - mMajorSkills = major; - mMinorSkills = minor; - - // Update misc skills with the remaining skills not in major or minor - std::set skillSet; - std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); - std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); - boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); - mMiscSkills.clear(); - for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) - { - int skill = *it; - if (skillSet.find(skill) == skillSet.end()) - mMiscSkills.push_back(skill); + if (id=="name") + setPlayerName (value); + else if (id=="race") + setText ("RaceText", value); + else if (id=="class") + setText ("ClassText", value); } - updateSkillArea(); -} - -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); - - // level progress - MyGUI::Widget* levelWidget; - for (int i=0; i<2; ++i) + void StatsWindow::setValue (const std::string& id, int value) { - getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); - levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); - levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + if (id=="level") + { + std::ostringstream text; + text << value; + setText("LevelText", text.str()); + } } - setFactions(PCstats.getFactionRanks()); - setExpelled(PCstats.getExpelled ()); + void StatsWindow::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value) + { + mSkillValues[parSkill] = value; + MyGUI::TextBox* widget = mSkillWidgetMap[(int)parSkill]; + if (widget) + { + float modified = value.getModified(), base = value.getBase(); + std::string text = boost::lexical_cast(std::floor(modified)); + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; - const std::string &signId = - MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); + widget->setCaption(text); + widget->_setWidgetState(state); + } + } - setBirthSign(signId); - setReputation (PCstats.getReputation ()); - setBounty (PCstats.getBounty ()); + void StatsWindow::configureSkills (const std::vector& major, const std::vector& minor) + { + mMajorSkills = major; + mMinorSkills = minor; + + // Update misc skills with the remaining skills not in major or minor + std::set skillSet; + std::copy(major.begin(), major.end(), std::inserter(skillSet, skillSet.begin())); + std::copy(minor.begin(), minor.end(), std::inserter(skillSet, skillSet.begin())); + boost::array::const_iterator end = ESM::Skill::sSkillIds.end(); + mMiscSkills.clear(); + for (boost::array::const_iterator it = ESM::Skill::sSkillIds.begin(); it != end; ++it) + { + int skill = *it; + if (skillSet.find(skill) == skillSet.end()) + mMiscSkills.push_back(skill); + } - if (mChanged) updateSkillArea(); -} - -void StatsWindow::setFactions (const FactionList& factions) -{ - if (mFactions != factions) - { - mFactions = factions; - mChanged = true; - } -} - -void StatsWindow::setExpelled (const std::set& expelled) -{ - if (mExpelled != expelled) - { - mExpelled = expelled; - mChanged = true; - } -} - -void StatsWindow::setBirthSign (const std::string& signId) -{ - if (signId != mBirthSignId) - { - mBirthSignId = signId; - mChanged = true; - } -} - -void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::ImageBox* separator = mSkillView->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); - mSkillWidgets.push_back(separator); - - coord1.top += separator->getHeight(); - coord2.top += separator->getHeight(); -} - -void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* groupWidget = mSkillView->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); - groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - mSkillWidgets.push_back(groupWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; -} - -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 = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setCaption(value); - skillValueWidget->_setWidgetState(state); - skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - mSkillWidgets.push_back(skillValueWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillValueWidget; -} - -MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - MyGUI::TextBox* skillNameWidget; - - skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); - skillNameWidget->setCaption(text); - skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); - - mSkillWidgets.push_back(skillNameWidget); - - coord1.top += sLineHeight; - coord2.top += sLineHeight; - - return skillNameWidget; -} - -void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) -{ - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - { - addSeparator(coord1, coord2); } - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); - - SkillList::const_iterator end = skills.end(); - for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + void StatsWindow::onFrame () { - int skillId = *it; - if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes - continue; - assert(skillId >= 0 && skillId < ESM::Skill::Length); - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; - float base = stat.getBase(); - float modified = stat.getModified(); - int progressPercent = (modified - float(static_cast(modified))) * 100; + if (!mMainWidget->getVisible()) + return; - const MWWorld::ESMStore &esmStore = - MWBase::Environment::get().getWorld()->getStore(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - const ESM::Skill* skill = esmStore.get().find(skillId); - assert(skill); + // level progress + MyGUI::Widget* levelWidget; + for (int i=0; i<2; ++i) + { + getWidget(levelWidget, i==0 ? "Level_str" : "LevelText"); + levelWidget->setUserString("RangePosition_LevelProgress", boost::lexical_cast(PCstats.getLevelProgress())); + levelWidget->setUserString("Caption_LevelProgressText", boost::lexical_cast(PCstats.getLevelProgress()) + "/10"); + } - std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); - const ESM::Attribute* attr = - esmStore.get().find(skill->mData.mAttribute); - assert(attr); + const std::string &signId = + MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); - std::string state = "normal"; - if (modified > base) - state = "increased"; - else if (modified < base) - state = "decreased"; - MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), - boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); + + if (mChanged) + updateSkillArea(); + } + + void StatsWindow::setFactions (const FactionList& factions) + { + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } + } + + void StatsWindow::setExpelled (const std::set& expelled) + { + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } + } + + void StatsWindow::setBirthSign (const std::string& signId) + { + if (signId != mBirthSignId) + { + mBirthSignId = signId; + mChanged = true; + } + } + + void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::ImageBox* separator = mSkillView->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); + mSkillWidgets.push_back(separator); + + coord1.top += separator->getHeight(); + coord2.top += separator->getHeight(); + } + + void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* groupWidget = mSkillView->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); + groupWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + mSkillWidgets.push_back(groupWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + } + + 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 = mSkillView->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + skillValueWidget = mSkillView->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); + skillValueWidget->setCaption(value); + skillValueWidget->_setWidgetState(state); + skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + mSkillWidgets.push_back(skillValueWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillValueWidget; + } + + MyGUI::Widget* StatsWindow::addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + MyGUI::TextBox* skillNameWidget; + + skillNameWidget = mSkillView->createWidget("SandText", coord1 + MyGUI::IntSize(coord2.width, 0), MyGUI::Align::Default); + skillNameWidget->setCaption(text); + skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); + + mSkillWidgets.push_back(skillNameWidget); + + coord1.top += sLineHeight; + coord2.top += sLineHeight; + + return skillNameWidget; + } + + void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + { + addSeparator(coord1, coord2); + } + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString(titleId, titleDefault), coord1, coord2); + + SkillList::const_iterator end = skills.end(); + for (SkillList::const_iterator it = skills.begin(); it != end; ++it) + { + int skillId = *it; + if (skillId < 0 || skillId > ESM::Skill::Length) // Skip unknown skill indexes + continue; + assert(skillId >= 0 && skillId < ESM::Skill::Length); + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const MWMechanics::Stat &stat = mSkillValues.find(skillId)->second; + float base = stat.getBase(); + float modified = stat.getModified(); + int progressPercent = (modified - float(static_cast(modified))) * 100; + + const MWWorld::ESMStore &esmStore = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Skill* skill = esmStore.get().find(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = + esmStore.get().find(skill->mData.mAttribute); + assert(attr); + + std::string state = "normal"; + if (modified > base) + state = "increased"; + else if (modified < base) + state = "decreased"; + MyGUI::TextBox* widget = addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString(skillNameId, skillNameId), + boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + } + + mSkillWidgetMap[skillId] = widget; + } + } + + void StatsWindow::updateSkillArea() + { + mChanged = false; + + for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) + { + MyGUI::Gui::getInstance().destroyWidget(*it); + } + mSkillWidgets.clear(); + + mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); + mClientHeight = 0; + + const int valueSize = 40; + MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); + MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); + + if (!mMajorSkills.empty()) + addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); + + if (!mMinorSkills.empty()) + addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); + + if (!mMiscSkills.empty()) + addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); + + MWBase::World *world = MWBase::Environment::get().getWorld(); + const MWWorld::ESMStore &store = world->getStore(); + const ESM::NPC *player = + world->getPlayer().getPlayer().get()->mBase; + + // race tooltip + const ESM::Race* playerRace = store.get().find(player->mRace); + + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + getWidget(raceWidget, "Race_str"); + ToolTips::createRaceToolTip(raceWidget, playerRace); + + // class tooltip + MyGUI::Widget* classWidget; + + const ESM::Class *playerClass = + store.get().find(player->mClass); + + getWidget(classWidget, "ClassText"); + ToolTips::createClassToolTip(classWidget, *playerClass); + getWidget(classWidget, "Class_str"); + ToolTips::createClassToolTip(classWidget, *playerClass); + + if (!mFactions.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + { + const ESM::Faction *faction = + store.get().find(it->first); + MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->mName; + + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else + { + text += std::string("\n#BF9959") + faction->mRanks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); + } + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); + } + } + + if (!mBirthSignId.empty()) + { + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); + const ESM::BirthSign *sign = + store.get().find(mBirthSignId); + MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); + + ToolTips::createBirthsignToolTip(w, mBirthSignId); + } + + // Add a line separator if there are items above + if (!mSkillWidgets.empty()) + addSeparator(coord1, coord2); + + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), + boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); for (int i=0; i<2; ++i) { mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->mDescription); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", boost::lexical_cast(progressPercent)+"/100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("RangePosition_SkillProgress", boost::lexical_cast(progressPercent)); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); } - mSkillWidgetMap[skillId] = widget; - } -} + addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), + boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); -void StatsWindow::updateSkillArea() -{ - mChanged = false; - - for (std::vector::iterator it = mSkillWidgets.begin(); it != mSkillWidgets.end(); ++it) - { - MyGUI::Gui::getInstance().destroyWidget(*it); - } - mSkillWidgets.clear(); - - mSkillView->setViewOffset (MyGUI::IntPoint(0,0)); - mClientHeight = 0; - - const int valueSize = 40; - MyGUI::IntCoord coord1(10, 0, mSkillView->getWidth() - (10 + valueSize) - 24, 18); - MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); - - if (!mMajorSkills.empty()) - addSkills(mMajorSkills, "sSkillClassMajor", "Major Skills", coord1, coord2); - - if (!mMinorSkills.empty()) - addSkills(mMinorSkills, "sSkillClassMinor", "Minor Skills", coord1, coord2); - - if (!mMiscSkills.empty()) - addSkills(mMiscSkills, "sSkillClassMisc", "Misc Skills", coord1, coord2); - - MWBase::World *world = MWBase::Environment::get().getWorld(); - const MWWorld::ESMStore &store = world->getStore(); - const ESM::NPC *player = - world->getPlayer().getPlayer().get()->mBase; - - // race tooltip - const ESM::Race* playerRace = store.get().find(player->mRace); - - MyGUI::Widget* raceWidget; - getWidget(raceWidget, "RaceText"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - getWidget(raceWidget, "Race_str"); - ToolTips::createRaceToolTip(raceWidget, playerRace); - - // class tooltip - MyGUI::Widget* classWidget; - - const ESM::Class *playerClass = - store.get().find(player->mClass); - - getWidget(classWidget, "ClassText"); - ToolTips::createClassToolTip(classWidget, *playerClass); - getWidget(classWidget, "Class_str"); - ToolTips::createClassToolTip(classWidget, *playerClass); - - if (!mFactions.empty()) - { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); - std::set& expelled = PCstats.getExpelled (); - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = mFactions.end(); - for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) + for (int i=0; i<2; ++i) { - const ESM::Faction *faction = - store.get().find(it->first); - MyGUI::Widget* w = addItem(faction->mName, coord1, coord2); - - std::string text; - - text += std::string("#DDC79E") + faction->mName; - - if (expelled.find(it->first) != expelled.end()) - text += "\n#{sExpelled}"; - else - { - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - - if (it->second < 9) - { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute[0]); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute[1]); - assert(attr1 && attr2); - - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) - { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkills[i]]+"}"; - if (i<5) - text += ", "; - } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); - } - } - - w->setUserString("ToolTipType", "Layout"); - w->setUserString("ToolTipLayout", "TextToolTip"); - w->setUserString("Caption_Text", text); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); } + + mClientHeight = coord1.top; + + mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); } - if (!mBirthSignId.empty()) + void StatsWindow::onPinToggled() { - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addGroup(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBirthSign", "Sign"), coord1, coord2); - const ESM::BirthSign *sign = - store.get().find(mBirthSignId); - MyGUI::Widget* w = addItem(sign->mName, coord1, coord2); - - ToolTips::createBirthsignToolTip(w, mBirthSignId); + MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); } - - // Add a line separator if there are items above - if (!mSkillWidgets.empty()) - addSeparator(coord1, coord2); - - addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sReputation", "Reputation"), - boost::lexical_cast(static_cast(mReputation)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); - } - - addValueItem(MWBase::Environment::get().getWindowManager()->getGameSettingString("sBounty", "Bounty"), - boost::lexical_cast(static_cast(mBounty)), "normal", coord1, coord2); - - for (int i=0; i<2; ++i) - { - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); - mSkillWidgets[mSkillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); - } - - mClientHeight = coord1.top; - - mSkillView->setCanvasSize (mSkillView->getWidth(), std::max(mSkillView->getHeight(), mClientHeight)); -} - -void StatsWindow::onPinToggled() -{ - MWBase::Environment::get().getWindowManager()->setHMSVisibility(!mPinned); } diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index ab2936cfce..d4f8a25336 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -3,68 +3,71 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" -using namespace MWGui; - -TextInputDialog::TextInputDialog() - : WindowModal("openmw_text_input.layout") +namespace MWGui { - // Centre dialog - center(); - getWidget(mTextEdit, "TextEdit"); - mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); - - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); - - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -void TextInputDialog::setNextButtonShow(bool shown) -{ - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - - if (shown) - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); - else - okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); -} - -void TextInputDialog::setTextLabel(const std::string &label) -{ - setText("LabelT", label); -} - -void TextInputDialog::open() -{ - WindowModal::open(); - // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); -} - -// widget controls - -void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) -{ - if (mTextEdit->getCaption() == "") + TextInputDialog::TextInputDialog() + : WindowModal("openmw_text_input.layout") { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); - } - else - eventDone(this); -} + // Centre dialog + center(); -void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) -{ - if (mTextEdit->getCaption() == "") - { - MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + getWidget(mTextEdit, "TextEdit"); + mTextEdit->eventEditSelectAccept += newDelegate(this, &TextInputDialog::onTextAccepted); + + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); + + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); } - else - eventDone(this); + + void TextInputDialog::setNextButtonShow(bool shown) + { + MyGUI::Button* okButton; + getWidget(okButton, "OKButton"); + + if (shown) + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sNext", "")); + else + okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", "")); + } + + void TextInputDialog::setTextLabel(const std::string &label) + { + setText("LabelT", label); + } + + void TextInputDialog::open() + { + WindowModal::open(); + // Make sure the edit box has focus + MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + } + + // widget controls + + void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) + { + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); + } + + void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) + { + if (mTextEdit->getCaption() == "") + { + MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); + } + } diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index b72d27aeae..d86aa69412 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -9,761 +9,763 @@ #include "mapwindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; -using namespace MyGUI; - -ToolTips::ToolTips() : - Layout("openmw_tooltips.layout") - , mGameMode(true) - , mFullHelp(false) - , mEnabled(true) - , mFocusToolTipX(0.0) - , mFocusToolTipY(0.0) - , mDelay(0.0) - , mRemainingDelay(0.0) - , mLastMouseX(0) - , mLastMouseY(0) - , mHorizontalScrollIndex(0) -{ - 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); - mMainWidget->setNeedMouseFocus(false); - - mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); - mRemainingDelay = mDelay; - - for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) - { - mMainWidget->getChildAt(i)->setVisible(false); - } -} - -void ToolTips::setEnabled(bool enabled) -{ - mEnabled = enabled; -} - -void ToolTips::onFrame(float frameDuration) +namespace MWGui { - while (mDynamicToolTipBox->getChildCount()) + ToolTips::ToolTips() : + Layout("openmw_tooltips.layout") + , mGameMode(true) + , mFullHelp(false) + , mEnabled(true) + , mFocusToolTipX(0.0) + , mFocusToolTipY(0.0) + , mDelay(0.0) + , mRemainingDelay(0.0) + , mLastMouseX(0) + , mLastMouseY(0) + , mHorizontalScrollIndex(0) { - MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); - } + getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); - // start by hiding everything - for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) - { - mMainWidget->getChildAt(i)->setVisible(false); - } + mDynamicToolTipBox->setVisible(false); - const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + // turn off mouse focus so that getMouseFocusWidget returns the correct widget, + // even if the mouse is over the tooltip + mDynamicToolTipBox->setNeedMouseFocus(false); + mMainWidget->setNeedMouseFocus(false); - if (!mEnabled) - { - return; - } + mDelay = Settings::Manager::getFloat("tooltip delay", "GUI"); + mRemainingDelay = mDelay; - if (!mGameMode) - { - const MyGUI::IntPoint& mousePos = InputManager::getInstance().getMousePosition(); - - if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) - || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) - || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) { - mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + mMainWidget->getChildAt(i)->setVisible(false); + } + } - if (mFocusObject.isEmpty ()) - return; + void ToolTips::setEnabled(bool enabled) + { + mEnabled = enabled; + } - const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + void ToolTips::onFrame(float frameDuration) + { - IntSize tooltipSize; - if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) - { - setCoord(0, 0, 300, 300); - mDynamicToolTipBox->setVisible(true); - ToolTipInfo info; - info.caption=mFocusObject.getCellRef().mRefID; - info.icon=""; - tooltipSize = createToolTip(info); - } - else - 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); + while (mDynamicToolTipBox->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); } + // start by hiding everything + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } + + const MyGUI::IntSize &viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + if (!mEnabled) + { + return; + } + + if (!mGameMode) + { + const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); + + if (MWBase::Environment::get().getWindowManager()->getWorldMouseOver() && ((MWBase::Environment::get().getWindowManager()->getMode() == GM_Console) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Container) + || (MWBase::Environment::get().getWindowManager()->getMode() == GM_Inventory))) + { + mFocusObject = MWBase::Environment::get().getWorld()->getFacedObject(); + + if (mFocusObject.isEmpty ()) + return; + + const MWWorld::Class& objectclass = MWWorld::Class::get (mFocusObject); + + MyGUI::IntSize tooltipSize; + if ((!objectclass.hasToolTip(mFocusObject))&&(MWBase::Environment::get().getWindowManager()->getMode() == GM_Console)) + { + setCoord(0, 0, 300, 300); + mDynamicToolTipBox->setVisible(true); + ToolTipInfo info; + info.caption=mFocusObject.getCellRef().mRefID; + info.icon=""; + tooltipSize = createToolTip(info); + } + else + tooltipSize = getToolTipViaPtr(true); + + MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition() + MyGUI::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 + { + const MyGUI::IntPoint& lastPressed = MyGUI::InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + + if (mousePos == lastPressed) // mouseclick makes tooltip disappear + return; + + if (mousePos.left == mLastMouseX && mousePos.top == mLastMouseY) + { + mRemainingDelay -= frameDuration; + } + else + { + mHorizontalScrollIndex = 0; + mRemainingDelay = mDelay; + } + mLastMouseX = mousePos.left; + mLastMouseY = mousePos.top; + + + if (mRemainingDelay > 0) + return; + + MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getMouseFocusWidget(); + if (focus == 0) + return; + + MyGUI::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"); + + if (type == "") + { + return; + } + + + // special handling for markers on the local map: the tooltip should only be visible + // if the marker is not hidden due to the fog of war. + if (focus->getUserString ("IsMarker") == "true") + { + LocalMapBase::MarkerPosition pos = *focus->getUserData(); + + if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) + return; + } + + if (type == "ItemPtr") + { + mFocusObject = *focus->getUserData(); + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "ToolTipInfo") + { + tooltipSize = createToolTip(*focus->getUserData()); + } + else if (type == "AvatarItemSelection") + { + MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); + MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); + int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); + int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); + MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); + + mFocusObject = item; + if (!mFocusObject.isEmpty ()) + tooltipSize = getToolTipViaPtr(false); + } + else if (type == "Spell") + { + ToolTipInfo info; + + const ESM::Spell *spell = + MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); + info.caption = spell->mName; + Widgets::SpellEffectList effects; + std::vector::const_iterator end = spell->mEffects.mList.end(); + for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + { + Widgets::SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); + params.mNoTarget = false; + 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); + + std::map userStrings = focus->getUserStrings(); + for (std::map::iterator it = userStrings.begin(); + it != userStrings.end(); ++it) + { + if (it->first == "ToolTipType" + || it->first == "ToolTipLayout" + || it->first == "IsMarker") + 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); + } + + tooltipSize = tooltip->getSize(); + + tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); + } + else + throw std::runtime_error ("unknown tooltip type"); + + MyGUI::IntPoint tooltipPosition = MyGUI::InputManager::getInstance().getMousePosition() + MyGUI::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 { - 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 (!mFocusObject.isEmpty()) { - mRemainingDelay -= frameDuration; + MyGUI::IntSize tooltipSize = getToolTipViaPtr(); + + setCoord(viewSize.width/2 - tooltipSize.width/2, + std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), + tooltipSize.width, + tooltipSize.height); + + mDynamicToolTipBox->setVisible(true); } - else - { - mHorizontalScrollIndex = 0; - mRemainingDelay = mDelay; - } - mLastMouseX = mousePos.left; - mLastMouseY = mousePos.top; - - - 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) - return; - ++i; - } - - std::string type = focus->getUserString("ToolTipType"); - std::string text = focus->getUserString("ToolTipText"); - - if (type == "") - { - return; - } - - - // special handling for markers on the local map: the tooltip should only be visible - // if the marker is not hidden due to the fog of war. - if (focus->getUserString ("IsMarker") == "true") - { - LocalMapBase::MarkerPosition pos = *focus->getUserData(); - - if (!MWBase::Environment::get().getWorld ()->isPositionExplored (pos.nX, pos.nY, pos.cellX, pos.cellY, pos.interior)) - return; - } - - if (type == "ItemPtr") - { - mFocusObject = *focus->getUserData(); - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "ToolTipInfo") - { - tooltipSize = createToolTip(*focus->getUserData()); - } - else if (type == "AvatarItemSelection") - { - MyGUI::IntCoord avatarPos = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarScreenCoord (); - MyGUI::IntPoint relMousePos = MyGUI::InputManager::getInstance ().getMousePosition () - MyGUI::IntPoint(avatarPos.left, avatarPos.top); - int realX = int(float(relMousePos.left) / float(avatarPos.width) * 512.f ); - int realY = int(float(relMousePos.top) / float(avatarPos.height) * 1024.f ); - MWWorld::Ptr item = MWBase::Environment::get().getWindowManager()->getInventoryWindow ()->getAvatarSelectedItem (realX, realY); - - mFocusObject = item; - if (!mFocusObject.isEmpty ()) - tooltipSize = getToolTipViaPtr(false); - } - else if (type == "Spell") - { - ToolTipInfo info; - - const ESM::Spell *spell = - MWBase::Environment::get().getWorld()->getStore().get().find(focus->getUserString("Spell")); - info.caption = spell->mName; - Widgets::SpellEffectList effects; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) - { - Widgets::SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mIsConstant = (spell->mData.mType == ESM::Spell::ST_Ability); - params.mNoTarget = false; - 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); - - std::map userStrings = focus->getUserStrings(); - for (std::map::iterator it = userStrings.begin(); - it != userStrings.end(); ++it) - { - if (it->first == "ToolTipType" - || it->first == "ToolTipLayout" - || it->first == "IsMarker") - 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); - } - - tooltipSize = tooltip->getSize(); - - 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 + + void ToolTips::enterGameMode() { - if (!mFocusObject.isEmpty()) + mGameMode = true; + } + + void ToolTips::enterGuiMode() + { + mGameMode = false; + } + + void ToolTips::setFocusObject(const MWWorld::Ptr& focus) + { + mFocusObject = focus; + } + + MyGUI::IntSize ToolTips::getToolTipViaPtr (bool image) + { + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); + + MyGUI::IntSize tooltipSize; + + const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); + if (!object.hasToolTip(mFocusObject)) + { + mDynamicToolTipBox->setVisible(false); + } + else { - IntSize tooltipSize = getToolTipViaPtr(); - - setCoord(viewSize.width/2 - tooltipSize.width/2, - std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), - tooltipSize.width, - tooltipSize.height); - mDynamicToolTipBox->setVisible(true); + + ToolTipInfo info = object.getToolTipInfo(mFocusObject); + if (!image) + info.icon = ""; + tooltipSize = createToolTip(info); + } + + 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'; } } -} -void ToolTips::enterGameMode() -{ - mGameMode = true; -} - -void ToolTips::enterGuiMode() -{ - mGameMode = false; -} - -void ToolTips::setFocusObject(const MWWorld::Ptr& focus) -{ - mFocusObject = focus; -} - -IntSize ToolTips::getToolTipViaPtr (bool image) -{ - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - IntSize tooltipSize; - - const MWWorld::Class& object = MWWorld::Class::get (mFocusObject); - if (!object.hasToolTip(mFocusObject)) - { - mDynamicToolTipBox->setVisible(false); - } - else + MyGUI::IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { mDynamicToolTipBox->setVisible(true); - ToolTipInfo info = object.getToolTipInfo(mFocusObject); - if (!image) - info.icon = ""; - tooltipSize = createToolTip(info); - } + std::string caption = info.caption; + std::string image = info.icon; + int imageSize = (image != "") ? info.imageSize : 0; + std::string text = info.text; - return tooltipSize; -} + // remove the first newline (easier this way) + if (text.size() > 0 && text[0] == '\n') + text.erase(0, 1); -void ToolTips::findImageExtension(std::string& image) -{ - int len = image.size(); - if (len < 4) return; + if(caption.size() > 0 && isalnum(caption[0])) + caption[0] = toupper(caption[0]); - 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::createToolTip(const MWGui::ToolTipInfo& info) -{ - mDynamicToolTipBox->setVisible(true); - - std::string caption = info.caption; - std::string image = info.icon; - int imageSize = (image != "") ? info.imageSize : 0; - std::string text = info.text; - - // remove the first newline (easier this way) - if (text.size() > 0 && text[0] == '\n') - text.erase(0, 1); - - if(caption.size() > 0 && isalnum(caption[0])) - caption[0] = toupper(caption[0]); - - const ESM::Enchantment* enchant = 0; - const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); - if (info.enchant != "") - { - enchant = store.get().find(info.enchant); - if (enchant->mData.mType == ESM::Enchantment::CastOnce) - text += "\n#{sItemCastOnce}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) - text += "\n#{sItemCastWhenStrikes}"; - else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) - text += "\n#{sItemCastWhenUsed}"; - else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) - text += "\n#{sItemCastConstant}"; - } - - // this the maximum width of the tooltip before it starts word-wrapping - setCoord(0, 0, 300, 300); - - const IntPoint padding(8, 8); - - const int maximumWidth = 500; - - const int imageCaptionHPadding = (caption != "" ? 8 : 0); - const int imageCaptionVPadding = (caption != "" ? 4 : 0); - - 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->setCaptionWithReplacing(caption); - IntSize captionSize = captionWidget->getTextSize(); - - 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"); - textWidget->setProperty("MultiLine", "true"); - textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); - textWidget->setCaptionWithReplacing(text); - textWidget->setTextAlign(Align::HCenter | Align::Top); - IntSize textSize = textWidget->getTextSize(); - - captionSize += IntSize(imageSize, 0); // adjust for image - IntSize totalSize = IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), - ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); - - if (!info.effects.empty()) - { - 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->setEffectList(info.effects); - - std::vector effectItems; - effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); - totalSize.height += coord.top-6; - totalSize.width = std::max(totalSize.width, coord.width); - } - - if (info.enchant != "") - { - assert(enchant); - Widget* enchantArea = mDynamicToolTipBox->createWidget("", - IntCoord(0, totalSize.height, 300, 300-totalSize.height), - Align::Stretch, "ToolTipEnchantArea"); - - IntCoord coord(0, 6, totalSize.width, 24); - - Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget - ("MW_StatName", coord, Align::Default, "ToolTipEnchantWidget"); - enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); - - std::vector enchantEffectItems; - int flag = (enchant->mData.mType == 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); - - if (enchant->mData.mType == ESM::Enchantment::WhenStrikes - || enchant->mData.mType == ESM::Enchantment::WhenUsed) + const ESM::Enchantment* enchant = 0; + const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + if (info.enchant != "") { - int maxCharge = enchant->mData.mCharge; - int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; - - const int chargeWidth = 204; - - TextBox* chargeText = enchantArea->createWidget("SandText", IntCoord(0, 0, 10, 18), Align::Default, "ToolTipEnchantChargeText"); - chargeText->setCaptionWithReplacing("#{sCharges}"); - - 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; - 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; + enchant = store.get().find(info.enchant); + if (enchant->mData.mType == ESM::Enchantment::CastOnce) + text += "\n#{sItemCastOnce}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes) + text += "\n#{sItemCastWhenStrikes}"; + else if (enchant->mData.mType == ESM::Enchantment::WhenUsed) + text += "\n#{sItemCastWhenUsed}"; + else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect) + text += "\n#{sItemCastConstant}"; } - } - captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, - (captionHeight-captionSize.height)/2, - captionSize.width-imageSize, - captionSize.height); + // this the maximum width of the tooltip before it starts word-wrapping + setCoord(0, 0, 300, 300); - //if its too long we do hscroll with the caption - if (captionSize.width > maximumWidth) - { - mHorizontalScrollIndex = mHorizontalScrollIndex + 2; - if (mHorizontalScrollIndex > captionSize.width){ - mHorizontalScrollIndex = -totalSize.width; - } - int horizontal_scroll = mHorizontalScrollIndex; - if (horizontal_scroll < 40){ - horizontal_scroll = 40; - }else{ - horizontal_scroll = 80 - mHorizontalScrollIndex; - } - captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); - } else { - captionWidget->setPosition (captionWidget->getPosition() + padding); - } + const MyGUI::IntPoint padding(8, 8); - textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + const int maximumWidth = 500; - 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); - } + const int imageCaptionHPadding = (caption != "" ? 8 : 0); + const int imageCaptionVPadding = (caption != "" ? 4 : 0); - totalSize += IntSize(padding.left*2, padding.top*2); + std::string realImage = "icons\\" + image; + findImageExtension(realImage); - return totalSize; -} + MyGUI::EditBox* captionWidget = mDynamicToolTipBox->createWidget("NormalText", MyGUI::IntCoord(0, 0, 300, 300), MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipCaption"); + captionWidget->setProperty("Static", "true"); + captionWidget->setCaptionWithReplacing(caption); + MyGUI::IntSize captionSize = captionWidget->getTextSize(); -std::string ToolTips::toString(const float value) -{ - std::ostringstream stream; - stream << std::setprecision(3) << value; - return stream.str(); -} + int captionHeight = std::max(caption != "" ? captionSize.height : 0, imageSize); -std::string ToolTips::toString(const int value) -{ - std::ostringstream stream; - stream << value; - return stream.str(); -} + MyGUI::EditBox* textWidget = mDynamicToolTipBox->createWidget("SandText", MyGUI::IntCoord(0, captionHeight+imageCaptionVPadding, 300, 300-captionHeight-imageCaptionVPadding), MyGUI::Align::Stretch, "ToolTipText"); + textWidget->setProperty("Static", "true"); + textWidget->setProperty("MultiLine", "true"); + textWidget->setProperty("WordWrap", info.wordWrap ? "true" : "false"); + textWidget->setCaptionWithReplacing(text); + textWidget->setTextAlign(MyGUI::Align::HCenter | MyGUI::Align::Top); + MyGUI::IntSize textSize = textWidget->getTextSize(); -std::string ToolTips::getValueString(const int value, const std::string& prefix) -{ - if (value == 0) - return ""; - else - return "\n" + prefix + ": " + toString(value); -} + captionSize += MyGUI::IntSize(imageSize, 0); // adjust for image + MyGUI::IntSize totalSize = MyGUI::IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), + ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); -std::string ToolTips::getMiscString(const std::string& text, const std::string& prefix) -{ - if (text == "") - return ""; - else - 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; -} - -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; -} - -void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) -{ - if (skillId == -1) - return; - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; - const ESM::Skill* skill = store.get().find(skillId); - assert(skill); - - const ESM::Attribute* attr = - store.get().find(skill->mData.mAttribute); - 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->mDescription); - widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); - widget->setUserString("ImageTexture_SkillNoProgressImage", icon); -} - -void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) -{ - if (attributeId == -1) - return; - - std::string icon = ESM::Attribute::sAttributeIcons[attributeId]; - std::string name = ESM::Attribute::sGmstAttributeIds[attributeId]; - std::string desc = ESM::Attribute::sGmstAttributeDescIds[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 - const MWWorld::Store &skills = - MWBase::Environment::get().getWorld()->getStore().get(); - - MWWorld::Store::iterator it = skills.begin(); - for (; it != skills.end(); ++it) - { - if (it->mData.mSpecialization == specId) - specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; - } - widget->setUserString("Caption_CenteredCaptionText", specText); - widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); - widget->setUserString("ToolTipType", "Layout"); -} - -void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) -{ - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::BirthSign *sign = store.get().find(birthsignId); - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "BirthSignToolTip"); - std::string image = sign->mTexture; - image.replace(image.size()-3, 3, "dds"); - widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); - std::string text; - - text += sign->mName; - text += "\n#BF9959" + sign->mDescription; - - std::vector abilities, powers, spells; - - std::vector::const_iterator it = sign->mPowers.mList.begin(); - std::vector::const_iterator end = sign->mPowers.mList.end(); - for (; it != end; ++it) - { - const std::string &spellId = *it; - const ESM::Spell *spell = store.get().search(spellId); - if (!spell) - continue; // Skip spells which cannot be found - ESM::Spell::SpellType type = static_cast(spell->mData.mType); - 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 (!info.effects.empty()) { - if (it == categories[category].spells.begin()) - { - text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; - } + MyGUI::Widget* effectArea = mDynamicToolTipBox->createWidget("", + MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::Align::Stretch, "ToolTipEffectArea"); + MyGUI::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, MyGUI::Align::Default, "ToolTipEffectsWidget"); + effectsWidget->setEffectList(info.effects); + + std::vector effectItems; + effectsWidget->createEffectWidgets(effectItems, effectArea, coord, true, info.isPotion ? Widgets::MWEffectList::EF_NoTarget : 0); + totalSize.height += coord.top-6; + totalSize.width = std::max(totalSize.width, coord.width); + } + + if (info.enchant != "") + { + assert(enchant); + MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget("", + MyGUI::IntCoord(0, totalSize.height, 300, 300-totalSize.height), + MyGUI::Align::Stretch, "ToolTipEnchantArea"); + + MyGUI::IntCoord coord(0, 6, totalSize.width, 24); + + Widgets::MWEffectListPtr enchantWidget = enchantArea->createWidget + ("MW_StatName", coord, MyGUI::Align::Default, "ToolTipEnchantWidget"); + enchantWidget->setEffectList(Widgets::MWEffectList::effectListFromESM(&enchant->mEffects)); + + std::vector enchantEffectItems; + int flag = (enchant->mData.mType == 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); + + if (enchant->mData.mType == ESM::Enchantment::WhenStrikes + || enchant->mData.mType == ESM::Enchantment::WhenUsed) + { + int maxCharge = enchant->mData.mCharge; + int charge = (info.remainingEnchantCharge == -1) ? maxCharge : info.remainingEnchantCharge; + + const int chargeWidth = 204; + + MyGUI::TextBox* chargeText = enchantArea->createWidget("SandText", MyGUI::IntCoord(0, 0, 10, 18), MyGUI::Align::Default, "ToolTipEnchantChargeText"); + chargeText->setCaptionWithReplacing("#{sCharges}"); + + 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); + + MyGUI::IntCoord chargeCoord; + if (totalSize.width < chargeWidth) + { + totalSize.width = chargeWidth; + chargeCoord = MyGUI::IntCoord(0, coord.top+6, chargeWidth, 18); + } + else + { + chargeCoord = MyGUI::IntCoord((totalSize.width - chargeAndTextWidth)/2 + chargeTextWidth, coord.top+6, chargeWidth, 18); + } + Widgets::MWDynamicStatPtr chargeWidget = enchantArea->createWidget + ("MW_ChargeBar", chargeCoord, MyGUI::Align::Default, "ToolTipEnchantCharge"); + chargeWidget->setValue(charge, charge); + totalSize.height += 24; + } + } + + captionWidget->setCoord( (totalSize.width - captionSize.width)/2 + imageSize, + (captionHeight-captionSize.height)/2, + captionSize.width-imageSize, + captionSize.height); + + //if its too long we do hscroll with the caption + if (captionSize.width > maximumWidth) + { + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (MyGUI::IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + } else { + captionWidget->setPosition (captionWidget->getPosition() + padding); + } + + textWidget->setPosition (textWidget->getPosition() + MyGUI::IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter + + if (image != "") + { + MyGUI::ImageBox* imageWidget = mDynamicToolTipBox->createWidget("ImageBox", + MyGUI::IntCoord((totalSize.width - captionSize.width - imageCaptionHPadding)/2, 0, imageSize, imageSize), + MyGUI::Align::Left | MyGUI::Align::Top, "ToolTipImage"); + imageWidget->setImageTexture(realImage); + imageWidget->setPosition (imageWidget->getPosition() + padding); + } + + totalSize += MyGUI::IntSize(padding.left*2, padding.top*2); + + return totalSize; + } + + 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, const std::string& prefix) + { + if (value == 0) + return ""; + else + 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; + } + + std::string ToolTips::getCountString(const int value) + { + if (value == 1) + return ""; + else + return " (" + boost::lexical_cast(value) + ")"; + } + + void ToolTips::toggleFullHelp() + { + mFullHelp = !mFullHelp; + } + + 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; + } + + void ToolTips::createSkillToolTip(MyGUI::Widget* widget, int skillId) + { + if (skillId == -1) + return; + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const std::string &skillNameId = ESM::Skill::sSkillNameIds[skillId]; + const ESM::Skill* skill = store.get().find(skillId); + assert(skill); + + const ESM::Attribute* attr = + store.get().find(skill->mData.mAttribute); + 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->mDescription); + widget->setUserString("Caption_SkillNoProgressAttribute", "#{sGoverningAttribute}: #{" + attr->mName + "}"); + widget->setUserString("ImageTexture_SkillNoProgressImage", icon); + } + + void ToolTips::createAttributeToolTip(MyGUI::Widget* widget, int attributeId) + { + if (attributeId == -1) + return; + + std::string icon = ESM::Attribute::sAttributeIcons[attributeId]; + std::string name = ESM::Attribute::sGmstAttributeIds[attributeId]; + std::string desc = ESM::Attribute::sGmstAttributeDescIds[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 + const MWWorld::Store &skills = + MWBase::Environment::get().getWorld()->getStore().get(); + + MWWorld::Store::iterator it = skills.begin(); + for (; it != skills.end(); ++it) + { + if (it->mData.mSpecialization == specId) + specText += std::string("\n#{") + ESM::Skill::sSkillNameIds[it->mIndex] + "}"; + } + widget->setUserString("Caption_CenteredCaptionText", specText); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + widget->setUserString("ToolTipType", "Layout"); + } + + void ToolTips::createBirthsignToolTip(MyGUI::Widget* widget, const std::string& birthsignId) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::BirthSign *sign = store.get().find(birthsignId); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "BirthSignToolTip"); + std::string image = sign->mTexture; + image.replace(image.size()-3, 3, "dds"); + widget->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); + std::string text; + + text += sign->mName; + text += "\n#BF9959" + sign->mDescription; + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = sign->mPowers.mList.begin(); + std::vector::const_iterator end = sign->mPowers.mList.end(); + for (; it != end; ++it) + { const std::string &spellId = *it; + const ESM::Spell *spell = store.get().search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->mData.mType); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. - const ESM::Spell *spell = store.get().find(spellId); - text += "\n#BF9959" + spell->mName; + 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.get().find(spellId); + text += "\n#BF9959" + spell->mName; + } + } + + widget->setUserString("Caption_BirthSignText", text); + } + + void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) + { + widget->setUserString("Caption_CenteredCaption", playerRace->mName); + widget->setUserString("Caption_CenteredCaptionText", playerRace->mDescription); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); + } + + void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) + { + if (playerClass.mName == "") + return; + + int spec = playerClass.mData.mSpecialization; + 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.mName); + widget->setUserString("Caption_ClassDescription", playerClass.mDescription); + widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "ClassToolTip"); + } + + void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) + { + const ESM::MagicEffect* effect = + MWBase::Environment::get().getWorld ()->getStore ().get().find(id); + const std::string &name = ESM::MagicEffect::effectIdToString (id); + + std::string icon = effect->mIcon; + + int slashPos = icon.find("\\"); + icon.insert(slashPos+1, "b_"); + + icon[icon.size()-3] = 'd'; + icon[icon.size()-2] = 'd'; + icon[icon.size()-1] = 's'; + + icon = "icons\\" + icon; + + std::vector schools; + schools.push_back ("#{sSchoolAlteration}"); + schools.push_back ("#{sSchoolConjuration}"); + schools.push_back ("#{sSchoolDestruction}"); + schools.push_back ("#{sSchoolIllusion}"); + schools.push_back ("#{sSchoolMysticism}"); + schools.push_back ("#{sSchoolRestoration}"); + + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); + widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); + widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); + widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]); + widget->setUserString("ImageTexture_MagicEffectImage", icon); + } + + void ToolTips::setDelay(float delay) + { + mDelay = delay; + mRemainingDelay = mDelay; } - widget->setUserString("Caption_BirthSignText", text); -} - -void ToolTips::createRaceToolTip(MyGUI::Widget* widget, const ESM::Race* playerRace) -{ - widget->setUserString("Caption_CenteredCaption", playerRace->mName); - widget->setUserString("Caption_CenteredCaptionText", playerRace->mDescription); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "TextWithCenteredCaptionToolTip"); -} - -void ToolTips::createClassToolTip(MyGUI::Widget* widget, const ESM::Class& playerClass) -{ - if (playerClass.mName == "") - return; - - int spec = playerClass.mData.mSpecialization; - 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.mName); - widget->setUserString("Caption_ClassDescription", playerClass.mDescription); - widget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "ClassToolTip"); -} - -void ToolTips::createMagicEffectToolTip(MyGUI::Widget* widget, short id) -{ - const ESM::MagicEffect* effect = - MWBase::Environment::get().getWorld ()->getStore ().get().find(id); - const std::string &name = ESM::MagicEffect::effectIdToString (id); - - std::string icon = effect->mIcon; - - int slashPos = icon.find("\\"); - icon.insert(slashPos+1, "b_"); - - icon[icon.size()-3] = 'd'; - icon[icon.size()-2] = 'd'; - icon[icon.size()-1] = 's'; - - icon = "icons\\" + icon; - - std::vector schools; - schools.push_back ("#{sSchoolAlteration}"); - schools.push_back ("#{sSchoolConjuration}"); - schools.push_back ("#{sSchoolDestruction}"); - schools.push_back ("#{sSchoolIllusion}"); - schools.push_back ("#{sSchoolMysticism}"); - schools.push_back ("#{sSchoolRestoration}"); - - widget->setUserString("ToolTipType", "Layout"); - widget->setUserString("ToolTipLayout", "MagicEffectToolTip"); - widget->setUserString("Caption_MagicEffectName", "#{" + name + "}"); - widget->setUserString("Caption_MagicEffectDescription", effect->mDescription); - widget->setUserString("Caption_MagicEffectSchool", "#{sSchool}: " + schools[effect->mData.mSchool]); - widget->setUserString("ImageTexture_MagicEffectImage", icon); -} - -void ToolTips::setDelay(float delay) -{ - mDelay = delay; - mRemainingDelay = mDelay; } diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index e6c8b1d77d..1662c0597d 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -12,882 +12,886 @@ #undef min #undef max -using namespace MWGui; -using namespace MWGui::Widgets; - -/* Helper functions */ - -/* - * Fixes the filename of a texture path to use the correct .dds extension. - * This is needed on some ESM entries which point to a .tga file instead. - */ -void MWGui::Widgets::fixTexturePath(std::string &path) +namespace MWGui { - int offset = path.rfind("."); - if (offset < 0) - return; - path.replace(offset, path.length() - offset, ".dds"); -} - -/* MWSkill */ - -MWSkill::MWSkill() - : mSkillId(ESM::Skill::Length) - , mSkillNameWidget(NULL) - , mSkillValueWidget(NULL) -{ -} - -void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) -{ - mSkillId = skill; - updateWidgets(); -} - -void MWSkill::setSkillNumber(int skill) -{ - if (skill < 0) - setSkillId(ESM::Skill::Length); - else if (skill < ESM::Skill::Length) - setSkillId(static_cast(skill)); - else - throw new std::runtime_error("Skill number out of range"); -} - -void MWSkill::setSkillValue(const SkillValue& value) -{ - mValue = value; - updateWidgets(); -} - -void MWSkill::updateWidgets() -{ - if (mSkillNameWidget) + namespace Widgets { - if (mSkillId == ESM::Skill::Length) + + /* Helper functions */ + + /* + * Fixes the filename of a texture path to use the correct .dds extension. + * This is needed on some ESM entries which point to a .tga file instead. + */ + void fixTexturePath(std::string &path) { - static_cast(mSkillNameWidget)->setCaption(""); - } - else - { - const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); - static_cast(mSkillNameWidget)->setCaption(name); - } - } - if (mSkillValueWidget) - { - SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); - static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); - if (modified > base) - mSkillValueWidget->_setWidgetState("increased"); - else if (modified < base) - mSkillValueWidget->_setWidgetState("decreased"); - else - mSkillValueWidget->_setWidgetState("normal"); - } -} - -void MWSkill::onClicked(MyGUI::Widget* _sender) -{ - eventClicked(this); -} - -MWSkill::~MWSkill() -{ -} - -void MWSkill::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mSkillNameWidget, "StatName"); - assignWidget(mSkillValueWidget, "StatValue"); - - MyGUI::Button* button; - assignWidget(button, "StatNameButton"); - if (button) - { - mSkillNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); - } - - button = 0; - assignWidget(button, "StatValueButton"); - if (button) - { - mSkillNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); - } -} - -/* MWAttribute */ - -MWAttribute::MWAttribute() - : mId(-1) - , mAttributeNameWidget(NULL) - , mAttributeValueWidget(NULL) -{ -} - -void MWAttribute::setAttributeId(int attributeId) -{ - mId = attributeId; - updateWidgets(); -} - -void MWAttribute::setAttributeValue(const AttributeValue& value) -{ - mValue = value; - updateWidgets(); -} - -void MWAttribute::onClicked(MyGUI::Widget* _sender) -{ - eventClicked(this); -} - -void MWAttribute::updateWidgets() -{ - if (mAttributeNameWidget) - { - if (mId < 0 || mId >= 8) - { - static_cast(mAttributeNameWidget)->setCaption(""); - } - else - { - static const char *attributes[8] = { - "sAttributeStrength", - "sAttributeIntelligence", - "sAttributeWillpower", - "sAttributeAgility", - "sAttributeSpeed", - "sAttributeEndurance", - "sAttributePersonality", - "sAttributeLuck" - }; - const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); - static_cast(mAttributeNameWidget)->setCaption(name); - } - } - if (mAttributeValueWidget) - { - AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); - static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); - if (modified > base) - mAttributeValueWidget->_setWidgetState("increased"); - else if (modified < base) - mAttributeValueWidget->_setWidgetState("decreased"); - else - mAttributeValueWidget->_setWidgetState("normal"); - } -} - -MWAttribute::~MWAttribute() -{ -} - -void MWAttribute::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mAttributeNameWidget, "StatName"); - assignWidget(mAttributeValueWidget, "StatValue"); - - MyGUI::Button* button; - assignWidget(button, "StatNameButton"); - if (button) - { - mAttributeNameWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); - } - - button = 0; - assignWidget(button, "StatValueButton"); - if (button) - { - mAttributeValueWidget = button; - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); - } -} - -/* MWSpell */ - -MWSpell::MWSpell() - : mSpellNameWidget(NULL) -{ -} - -void MWSpell::setSpellId(const std::string &spellId) -{ - mId = spellId; - updateWidgets(); -} - -void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) -{ - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Spell *spell = store.get().search(mId); - MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); - - MWSpellEffectPtr effect = NULL; - std::vector::const_iterator end = spell->mEffects.mList.end(); - for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) - { - effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - 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()); - } -} - -void MWSpell::updateWidgets() -{ - if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) - { - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::Spell *spell = store.get().search(mId); - if (spell) - static_cast(mSpellNameWidget)->setCaption(spell->mName); - else - static_cast(mSpellNameWidget)->setCaption(""); - } -} - -void MWSpell::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mSpellNameWidget, "StatName"); -} - -MWSpell::~MWSpell() -{ -} - -/* MWEffectList */ - -MWEffectList::MWEffectList() - : mEffectList(0) -{ -} - -void MWEffectList::setEffectList(const SpellEffectList& list) -{ - mEffectList = list; - updateWidgets(); -} - -void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* 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.... - MWSpellEffectPtr effect = NULL; - int maxwidth = coord.width; - - for (SpellEffectList::iterator it=mEffectList.begin(); - it != mEffectList.end(); ++it) - { - effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); - 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) - 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 MWEffectList::updateWidgets() -{ -} - -void MWEffectList::initialiseOverride() -{ - Base::initialiseOverride(); -} - -MWEffectList::~MWEffectList() -{ -} - -SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) -{ - SpellEffectList result; - std::vector::const_iterator end = effects->mList.end(); - for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) - { - SpellEffectParams params; - params.mEffectID = it->mEffectID; - params.mSkill = it->mSkill; - params.mAttribute = it->mAttribute; - params.mDuration = it->mDuration; - params.mMagnMin = it->mMagnMin; - params.mMagnMax = it->mMagnMax; - params.mRange = it->mRange; - params.mArea = it->mArea; - result.push_back(params); - } - return result; -} - -/* MWSpellEffect */ - -MWSpellEffect::MWSpellEffect() - : mImageWidget(NULL) - , mTextWidget(NULL) - , mRequestedWidth(0) -{ -} - -void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) -{ - mEffectParams = params; - updateWidgets(); -} - -void MWSpellEffect::updateWidgets() -{ - if (!mEffectParams.mKnown) - { - mTextWidget->setCaption ("?"); - mRequestedWidth = mTextWidget->getTextSize().width + 24; - mImageWidget->setImageTexture (""); - return; - } - - const MWWorld::ESMStore &store = - MWBase::Environment::get().getWorld()->getStore(); - - const ESM::MagicEffect *magicEffect = - store.get().search(mEffectParams.mEffectID); - - assert(magicEffect); - - std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); - std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); - std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; - std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); - std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); - - std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); - std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); - - if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); - } - if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); - } - - if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) - { - 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 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) - { - spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + int offset = path.rfind("."); + if (offset < 0) + return; + path.replace(offset, path.length() - offset, ".dds"); } - if (mEffectParams.mArea > 0) + /* MWSkill */ + + MWSkill::MWSkill() + : mSkillId(ESM::Skill::Length) + , mSkillNameWidget(NULL) + , mSkillValueWidget(NULL) { - spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; } - // potions have no target - if (!mEffectParams.mNoTarget) + void MWSkill::setSkillId(ESM::Skill::SkillEnum skill) { - std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); - if (mEffectParams.mRange == ESM::RT_Self) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); - else if (mEffectParams.mRange == ESM::RT_Touch) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); - else if (mEffectParams.mRange == ESM::RT_Target) - spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); + mSkillId = skill; + updateWidgets(); } - } - static_cast(mTextWidget)->setCaptionWithReplacing(spellLine); - mRequestedWidth = mTextWidget->getTextSize().width + 24; - - std::string path = std::string("icons\\") + magicEffect->mIcon; - fixTexturePath(path); - mImageWidget->setImageTexture(path); -} - -MWSpellEffect::~MWSpellEffect() -{ -} - -void MWSpellEffect::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mTextWidget, "Text"); - assignWidget(mImageWidget, "Image"); -} - -/* MWDynamicStat */ - -MWDynamicStat::MWDynamicStat() -: mValue(0) -, mMax(1) -, mTextWidget(NULL) -, mBarWidget(NULL) -, mBarTextWidget(NULL) -{ -} - -void MWDynamicStat::setValue(int cur, int max) -{ - mValue = cur; - mMax = max; - - if (mBarWidget) - { - mBarWidget->setProgressRange(mMax); - mBarWidget->setProgressPosition(mValue); - } - - - if (mBarTextWidget) - { - if (mValue >= 0 && mMax > 0) + void MWSkill::setSkillNumber(int skill) { - std::stringstream out; - out << mValue << "/" << mMax; - static_cast(mBarTextWidget)->setCaption(out.str().c_str()); + if (skill < 0) + setSkillId(ESM::Skill::Length); + else if (skill < ESM::Skill::Length) + setSkillId(static_cast(skill)); + else + throw new std::runtime_error("Skill number out of range"); } - else - static_cast(mBarTextWidget)->setCaption(""); - } -} -void MWDynamicStat::setTitle(const std::string& text) -{ - if (mTextWidget) - static_cast(mTextWidget)->setCaption(text); -} -MWDynamicStat::~MWDynamicStat() -{ -} - -void MWDynamicStat::initialiseOverride() -{ - Base::initialiseOverride(); - - assignWidget(mTextWidget, "Text"); - assignWidget(mBarWidget, "Bar"); - assignWidget(mBarTextWidget, "BarText"); -} - - - - -// --------------------------------------------------------------------------------------------------------------------- - -void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) -{ - if (w->getParent () != 0) - { - Box* b = dynamic_cast(w->getParent()); - if (b) - b->notifyChildrenSizeChanged (); - else + void MWSkill::setSkillValue(const SkillValue& value) { - if (mExpandDirection == MyGUI::Align::Left) + mValue = value; + updateWidgets(); + } + + void MWSkill::updateWidgets() + { + if (mSkillNameWidget) { - int hdiff = getRequestedSize ().width - w->getSize().width; - w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0)); + if (mSkillId == ESM::Skill::Length) + { + static_cast(mSkillNameWidget)->setCaption(""); + } + else + { + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mSkillId], ""); + static_cast(mSkillNameWidget)->setCaption(name); + } + } + if (mSkillValueWidget) + { + SkillValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mSkillValueWidget)->setCaption(boost::lexical_cast(modified)); + if (modified > base) + mSkillValueWidget->_setWidgetState("increased"); + else if (modified < base) + mSkillValueWidget->_setWidgetState("decreased"); + else + mSkillValueWidget->_setWidgetState("normal"); } - w->setSize(getRequestedSize ()); } - } -} - -MyGUI::IntSize AutoSizedTextBox::getRequestedSize() -{ - return getTextSize(); -} - -void AutoSizedTextBox::setCaption(const MyGUI::UString& _value) -{ - TextBox::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - TextBox::setPropertyOverride (_key, _value); - } -} - -MyGUI::IntSize AutoSizedEditBox::getRequestedSize() -{ - if (getAlign().isHStretch()) - throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); - return MyGUI::IntSize(getSize().width, getTextSize().height); -} - -void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) -{ - EditBox::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - EditBox::setPropertyOverride (_key, _value); - } -} - - -MyGUI::IntSize AutoSizedButton::getRequestedSize() -{ - MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(24,0); - size.height = std::max(24, size.height); - return size; -} - -void AutoSizedButton::setCaption(const MyGUI::UString& _value) -{ - Button::setCaption(_value); - - notifySizeChange (this); -} - -void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "ExpandDirection") - { - mExpandDirection = MyGUI::Align::parse (_value); - } - else - { - Button::setPropertyOverride (_key, _value); - } -} - -Box::Box() - : mSpacing(4) - , mPadding(0) - , mAutoResize(false) -{ - -} - -void Box::notifyChildrenSizeChanged () -{ - align(); -} - -void Box::_setPropertyImpl(const std::string& _key, const std::string& _value) -{ - if (_key == "Spacing") - mSpacing = MyGUI::utility::parseValue(_value); - else if (_key == "Padding") - mPadding = MyGUI::utility::parseValue(_value); - else if (_key == "AutoResize") - mAutoResize = MyGUI::utility::parseValue(_value); -} - -void HBox::align () -{ - unsigned int count = getChildCount (); - size_t h_stretched_count = 0; - int total_width = 0; - int total_height = 0; - std::vector< std::pair > sizes; - - for (unsigned int i = 0; i < count; ++i) - { - MyGUI::Widget* w = getChildAt(i); - bool hstretch = w->getUserString ("HStretch") == "true"; - h_stretched_count += hstretch; - AutoSizedWidget* aw = dynamic_cast(w); - if (aw) + void MWSkill::onClicked(MyGUI::Widget* _sender) { - sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); - total_width += aw->getRequestedSize ().width; - total_height = std::max(total_height, aw->getRequestedSize ().height); + eventClicked(this); } - else + + MWSkill::~MWSkill() { - sizes.push_back (std::make_pair(w->getSize(), hstretch)); - total_width += w->getSize().width; - if (!(w->getUserString("VStretch") == "true")) - total_height = std::max(total_height, w->getSize().height); } - if (i != count-1) - total_width += mSpacing; - } - - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) - { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); - return; - } - - - int curX = 0; - for (unsigned int i = 0; i < count; ++i) - { - if (i == 0) - curX += mPadding; - - MyGUI::Widget* w = getChildAt(i); - - bool vstretch = w->getUserString ("VStretch") == "true"; - int height = vstretch ? total_height : sizes[i].first.height; - - MyGUI::IntCoord widgetCoord; - widgetCoord.left = curX; - widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; - int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count - : sizes[i].first.width; - widgetCoord.width = width; - widgetCoord.height = height; - w->setCoord(widgetCoord); - curX += width; - - if (i != count-1) - curX += mSpacing; - } -} - -void HBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - Box::_setPropertyImpl (_key, _value); -} - -void HBox::setSize (const MyGUI::IntSize& _value) -{ - MyGUI::Widget::setSize (_value); - align(); -} - -void HBox::setCoord (const MyGUI::IntCoord& _value) -{ - MyGUI::Widget::setCoord (_value); - align(); -} - -void HBox::onWidgetCreated(MyGUI::Widget* _widget) -{ - align(); -} - -MyGUI::IntSize HBox::getRequestedSize () -{ - MyGUI::IntSize size(0,0); - for (unsigned int i = 0; i < getChildCount (); ++i) - { - AutoSizedWidget* w = dynamic_cast(getChildAt(i)); - if (w) + void MWSkill::initialiseOverride() { - MyGUI::IntSize requested = w->getRequestedSize (); - size.height = std::max(size.height, requested.height); - size.width = size.width + requested.width; - if (i != getChildCount()-1) - size.width += mSpacing; + Base::initialiseOverride(); + + assignWidget(mSkillNameWidget, "StatName"); + assignWidget(mSkillValueWidget, "StatValue"); + + MyGUI::Button* button; + assignWidget(button, "StatNameButton"); + if (button) + { + mSkillNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); + } + + button = 0; + assignWidget(button, "StatValueButton"); + if (button) + { + mSkillNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWSkill::onClicked); + } } - else + + /* MWAttribute */ + + MWAttribute::MWAttribute() + : mId(-1) + , mAttributeNameWidget(NULL) + , mAttributeValueWidget(NULL) { - MyGUI::IntSize requested = getChildAt(i)->getSize (); - size.height = std::max(size.height, requested.height); - - if (getChildAt(i)->getUserString("HStretch") != "true") - size.width = size.width + requested.width; - - if (i != getChildCount()-1) - size.width += mSpacing; } - size.height += mPadding*2; - size.width += mPadding*2; - } - return size; -} - - - -void VBox::align () -{ - unsigned int count = getChildCount (); - size_t v_stretched_count = 0; - int total_height = 0; - int total_width = 0; - std::vector< std::pair > sizes; - for (unsigned int i = 0; i < count; ++i) - { - MyGUI::Widget* w = getChildAt(i); - bool vstretch = w->getUserString ("VStretch") == "true"; - v_stretched_count += vstretch; - AutoSizedWidget* aw = dynamic_cast(w); - if (aw) + void MWAttribute::setAttributeId(int attributeId) { - sizes.push_back(std::make_pair(aw->getRequestedSize (), vstretch)); - total_height += aw->getRequestedSize ().height; - total_width = std::max(total_width, aw->getRequestedSize ().width); + mId = attributeId; + updateWidgets(); } - else + + void MWAttribute::setAttributeValue(const AttributeValue& value) { - sizes.push_back (std::make_pair(w->getSize(), vstretch)); - total_height += w->getSize().height; - - if (!(w->getUserString("HStretch") == "true")) - total_width = std::max(total_width, w->getSize().width); + mValue = value; + updateWidgets(); } - if (i != count-1) - total_height += mSpacing; - } + void MWAttribute::onClicked(MyGUI::Widget* _sender) + { + eventClicked(this); + } - if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) - { - setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); - return; - } + void MWAttribute::updateWidgets() + { + if (mAttributeNameWidget) + { + if (mId < 0 || mId >= 8) + { + static_cast(mAttributeNameWidget)->setCaption(""); + } + else + { + static const char *attributes[8] = { + "sAttributeStrength", + "sAttributeIntelligence", + "sAttributeWillpower", + "sAttributeAgility", + "sAttributeSpeed", + "sAttributeEndurance", + "sAttributePersonality", + "sAttributeLuck" + }; + const std::string &name = MWBase::Environment::get().getWindowManager()->getGameSettingString(attributes[mId], ""); + static_cast(mAttributeNameWidget)->setCaption(name); + } + } + if (mAttributeValueWidget) + { + AttributeValue::Type modified = mValue.getModified(), base = mValue.getBase(); + static_cast(mAttributeValueWidget)->setCaption(boost::lexical_cast(modified)); + if (modified > base) + mAttributeValueWidget->_setWidgetState("increased"); + else if (modified < base) + mAttributeValueWidget->_setWidgetState("decreased"); + else + mAttributeValueWidget->_setWidgetState("normal"); + } + } + + MWAttribute::~MWAttribute() + { + } + + void MWAttribute::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mAttributeNameWidget, "StatName"); + assignWidget(mAttributeValueWidget, "StatValue"); + + MyGUI::Button* button; + assignWidget(button, "StatNameButton"); + if (button) + { + mAttributeNameWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); + } + + button = 0; + assignWidget(button, "StatValueButton"); + if (button) + { + mAttributeValueWidget = button; + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWAttribute::onClicked); + } + } + + /* MWSpell */ + + MWSpell::MWSpell() + : mSpellNameWidget(NULL) + { + } + + void MWSpell::setSpellId(const std::string &spellId) + { + mId = spellId; + updateWidgets(); + } + + void MWSpell::createEffectWidgets(std::vector &effects, MyGUI::Widget* creator, MyGUI::IntCoord &coord, int flags) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); + MYGUI_ASSERT(spell, "spell with id '" << mId << "' not found"); + + MWSpellEffectPtr effect = NULL; + std::vector::const_iterator end = spell->mEffects.mList.end(); + for (std::vector::const_iterator it = spell->mEffects.mList.begin(); it != end; ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + 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()); + } + } + + void MWSpell::updateWidgets() + { + if (mSpellNameWidget && MWBase::Environment::get().getWindowManager()) + { + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::Spell *spell = store.get().search(mId); + if (spell) + static_cast(mSpellNameWidget)->setCaption(spell->mName); + else + static_cast(mSpellNameWidget)->setCaption(""); + } + } + + void MWSpell::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mSpellNameWidget, "StatName"); + } + + MWSpell::~MWSpell() + { + } + + /* MWEffectList */ + + MWEffectList::MWEffectList() + : mEffectList(0) + { + } + + void MWEffectList::setEffectList(const SpellEffectList& list) + { + mEffectList = list; + updateWidgets(); + } + + void MWEffectList::createEffectWidgets(std::vector &effects, MyGUI::Widget* 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.... + MWSpellEffectPtr effect = NULL; + int maxwidth = coord.width; + + for (SpellEffectList::iterator it=mEffectList.begin(); + it != mEffectList.end(); ++it) + { + effect = creator->createWidget("MW_EffectImage", coord, MyGUI::Align::Default); + 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) + 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 MWEffectList::updateWidgets() + { + } + + void MWEffectList::initialiseOverride() + { + Base::initialiseOverride(); + } + + MWEffectList::~MWEffectList() + { + } + + SpellEffectList MWEffectList::effectListFromESM(const ESM::EffectList* effects) + { + SpellEffectList result; + std::vector::const_iterator end = effects->mList.end(); + for (std::vector::const_iterator it = effects->mList.begin(); it != end; ++it) + { + SpellEffectParams params; + params.mEffectID = it->mEffectID; + params.mSkill = it->mSkill; + params.mAttribute = it->mAttribute; + params.mDuration = it->mDuration; + params.mMagnMin = it->mMagnMin; + params.mMagnMax = it->mMagnMax; + params.mRange = it->mRange; + params.mArea = it->mArea; + result.push_back(params); + } + return result; + } + + /* MWSpellEffect */ + + MWSpellEffect::MWSpellEffect() + : mImageWidget(NULL) + , mTextWidget(NULL) + , mRequestedWidth(0) + { + } + + void MWSpellEffect::setSpellEffect(const SpellEffectParams& params) + { + mEffectParams = params; + updateWidgets(); + } + + void MWSpellEffect::updateWidgets() + { + if (!mEffectParams.mKnown) + { + mTextWidget->setCaption ("?"); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + mImageWidget->setImageTexture (""); + return; + } + + const MWWorld::ESMStore &store = + MWBase::Environment::get().getWorld()->getStore(); + + const ESM::MagicEffect *magicEffect = + store.get().search(mEffectParams.mEffectID); + + assert(magicEffect); + + std::string pt = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoint", ""); + std::string pts = MWBase::Environment::get().getWindowManager()->getGameSettingString("spoints", ""); + std::string to = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sTo", "") + " "; + std::string sec = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("ssecond", ""); + std::string secs = " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sseconds", ""); + + std::string effectIDStr = ESM::MagicEffect::effectIdToString(mEffectParams.mEffectID); + std::string spellLine = MWBase::Environment::get().getWindowManager()->getGameSettingString(effectIDStr, ""); + + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetSkill) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Skill::sSkillNameIds[mEffectParams.mSkill], ""); + } + if (magicEffect->mData.mFlags & ESM::MagicEffect::TargetAttribute) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString(ESM::Attribute::sGmstAttributeIds[mEffectParams.mAttribute], ""); + } + + if ((mEffectParams.mMagnMin >= 0 || mEffectParams.mMagnMax >= 0) && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude)) + { + 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 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) + { + spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + boost::lexical_cast(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); + } + + if (mEffectParams.mArea > 0) + { + spellLine += " #{sin} " + boost::lexical_cast(mEffectParams.mArea) + " #{sfootarea}"; + } + + // potions have no target + if (!mEffectParams.mNoTarget) + { + std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sonword", ""); + if (mEffectParams.mRange == ESM::RT_Self) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeSelf", ""); + else if (mEffectParams.mRange == ESM::RT_Touch) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTouch", ""); + else if (mEffectParams.mRange == ESM::RT_Target) + spellLine += " " + on + " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sRangeTarget", ""); + } + } + + static_cast(mTextWidget)->setCaptionWithReplacing(spellLine); + mRequestedWidth = mTextWidget->getTextSize().width + 24; + + std::string path = std::string("icons\\") + magicEffect->mIcon; + fixTexturePath(path); + mImageWidget->setImageTexture(path); + } + + MWSpellEffect::~MWSpellEffect() + { + } + + void MWSpellEffect::initialiseOverride() + { + Base::initialiseOverride(); + + assignWidget(mTextWidget, "Text"); + assignWidget(mImageWidget, "Image"); + } + + /* MWDynamicStat */ + + MWDynamicStat::MWDynamicStat() + : mValue(0) + , mMax(1) + , mTextWidget(NULL) + , mBarWidget(NULL) + , mBarTextWidget(NULL) + { + } + + void MWDynamicStat::setValue(int cur, int max) + { + mValue = cur; + mMax = max; + + if (mBarWidget) + { + mBarWidget->setProgressRange(mMax); + mBarWidget->setProgressPosition(mValue); + } - int curY = 0; - for (unsigned int i = 0; i < count; ++i) - { - if (i==0) - curY += mPadding; + if (mBarTextWidget) + { + if (mValue >= 0 && mMax > 0) + { + std::stringstream out; + out << mValue << "/" << mMax; + static_cast(mBarTextWidget)->setCaption(out.str().c_str()); + } + else + static_cast(mBarTextWidget)->setCaption(""); + } + } + void MWDynamicStat::setTitle(const std::string& text) + { + if (mTextWidget) + static_cast(mTextWidget)->setCaption(text); + } - MyGUI::Widget* w = getChildAt(i); + MWDynamicStat::~MWDynamicStat() + { + } - bool hstretch = w->getUserString ("HStretch") == "true"; - int width = hstretch ? total_width : sizes[i].first.width; + void MWDynamicStat::initialiseOverride() + { + Base::initialiseOverride(); - MyGUI::IntCoord widgetCoord; - widgetCoord.top = curY; - widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; - int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count - : sizes[i].first.height; - widgetCoord.height = height; - widgetCoord.width = width; - w->setCoord(widgetCoord); - curY += height; + assignWidget(mTextWidget, "Text"); + assignWidget(mBarWidget, "Bar"); + assignWidget(mBarTextWidget, "BarText"); + } - if (i != count-1) - curY += mSpacing; + + + + // --------------------------------------------------------------------------------------------------------------------- + + void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) + { + if (w->getParent () != 0) + { + Box* b = dynamic_cast(w->getParent()); + if (b) + b->notifyChildrenSizeChanged (); + else + { + if (mExpandDirection == MyGUI::Align::Left) + { + int hdiff = getRequestedSize ().width - w->getSize().width; + w->setPosition(w->getPosition() - MyGUI::IntPoint(hdiff, 0)); + } + w->setSize(getRequestedSize ()); + } + } + } + + + MyGUI::IntSize AutoSizedTextBox::getRequestedSize() + { + return getTextSize(); + } + + void AutoSizedTextBox::setCaption(const MyGUI::UString& _value) + { + TextBox::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedTextBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + TextBox::setPropertyOverride (_key, _value); + } + } + + MyGUI::IntSize AutoSizedEditBox::getRequestedSize() + { + if (getAlign().isHStretch()) + throw std::runtime_error("AutoSizedEditBox can't have HStretch align (" + getName() + ")"); + return MyGUI::IntSize(getSize().width, getTextSize().height); + } + + void AutoSizedEditBox::setCaption(const MyGUI::UString& _value) + { + EditBox::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedEditBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + EditBox::setPropertyOverride (_key, _value); + } + } + + + MyGUI::IntSize AutoSizedButton::getRequestedSize() + { + MyGUI::IntSize size = getTextSize() + MyGUI::IntSize(24,0); + size.height = std::max(24, size.height); + return size; + } + + void AutoSizedButton::setCaption(const MyGUI::UString& _value) + { + Button::setCaption(_value); + + notifySizeChange (this); + } + + void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::string& _value) + { + if (_key == "ExpandDirection") + { + mExpandDirection = MyGUI::Align::parse (_value); + } + else + { + Button::setPropertyOverride (_key, _value); + } + } + + Box::Box() + : mSpacing(4) + , mPadding(0) + , mAutoResize(false) + { + + } + + void Box::notifyChildrenSizeChanged () + { + align(); + } + + void Box::_setPropertyImpl(const std::string& _key, const std::string& _value) + { + if (_key == "Spacing") + mSpacing = MyGUI::utility::parseValue(_value); + else if (_key == "Padding") + mPadding = MyGUI::utility::parseValue(_value); + else if (_key == "AutoResize") + mAutoResize = MyGUI::utility::parseValue(_value); + } + + void HBox::align () + { + unsigned int count = getChildCount (); + size_t h_stretched_count = 0; + int total_width = 0; + int total_height = 0; + std::vector< std::pair > sizes; + + for (unsigned int i = 0; i < count; ++i) + { + MyGUI::Widget* w = getChildAt(i); + bool hstretch = w->getUserString ("HStretch") == "true"; + h_stretched_count += hstretch; + AutoSizedWidget* aw = dynamic_cast(w); + if (aw) + { + sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); + total_width += aw->getRequestedSize ().width; + total_height = std::max(total_height, aw->getRequestedSize ().height); + } + else + { + sizes.push_back (std::make_pair(w->getSize(), hstretch)); + total_width += w->getSize().width; + if (!(w->getUserString("VStretch") == "true")) + total_height = std::max(total_height, w->getSize().height); + } + + if (i != count-1) + total_width += mSpacing; + } + + if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + { + setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + return; + } + + + int curX = 0; + for (unsigned int i = 0; i < count; ++i) + { + if (i == 0) + curX += mPadding; + + MyGUI::Widget* w = getChildAt(i); + + bool vstretch = w->getUserString ("VStretch") == "true"; + int height = vstretch ? total_height : sizes[i].first.height; + + MyGUI::IntCoord widgetCoord; + widgetCoord.left = curX; + widgetCoord.top = mPadding + (getSize().height-mPadding*2 - height) / 2; + int width = sizes[i].second ? sizes[i].first.width + (getSize().width-mPadding*2 - total_width)/h_stretched_count + : sizes[i].first.width; + widgetCoord.width = width; + widgetCoord.height = height; + w->setCoord(widgetCoord); + curX += width; + + if (i != count-1) + curX += mSpacing; + } + } + + void HBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + Box::_setPropertyImpl (_key, _value); + } + + void HBox::setSize (const MyGUI::IntSize& _value) + { + MyGUI::Widget::setSize (_value); + align(); + } + + void HBox::setCoord (const MyGUI::IntCoord& _value) + { + MyGUI::Widget::setCoord (_value); + align(); + } + + void HBox::onWidgetCreated(MyGUI::Widget* _widget) + { + align(); + } + + MyGUI::IntSize HBox::getRequestedSize () + { + MyGUI::IntSize size(0,0); + for (unsigned int i = 0; i < getChildCount (); ++i) + { + AutoSizedWidget* w = dynamic_cast(getChildAt(i)); + if (w) + { + MyGUI::IntSize requested = w->getRequestedSize (); + size.height = std::max(size.height, requested.height); + size.width = size.width + requested.width; + if (i != getChildCount()-1) + size.width += mSpacing; + } + else + { + MyGUI::IntSize requested = getChildAt(i)->getSize (); + size.height = std::max(size.height, requested.height); + + if (getChildAt(i)->getUserString("HStretch") != "true") + size.width = size.width + requested.width; + + if (i != getChildCount()-1) + size.width += mSpacing; + } + size.height += mPadding*2; + size.width += mPadding*2; + } + return size; + } + + + + + void VBox::align () + { + unsigned int count = getChildCount (); + size_t v_stretched_count = 0; + int total_height = 0; + int total_width = 0; + std::vector< std::pair > sizes; + for (unsigned int i = 0; i < count; ++i) + { + MyGUI::Widget* w = getChildAt(i); + bool vstretch = w->getUserString ("VStretch") == "true"; + v_stretched_count += vstretch; + AutoSizedWidget* aw = dynamic_cast(w); + if (aw) + { + sizes.push_back(std::make_pair(aw->getRequestedSize (), vstretch)); + total_height += aw->getRequestedSize ().height; + total_width = std::max(total_width, aw->getRequestedSize ().width); + } + else + { + sizes.push_back (std::make_pair(w->getSize(), vstretch)); + total_height += w->getSize().height; + + if (!(w->getUserString("HStretch") == "true")) + total_width = std::max(total_width, w->getSize().width); + } + + if (i != count-1) + total_height += mSpacing; + } + + if (mAutoResize && (total_width+mPadding*2 != getSize().width || total_height+mPadding*2 != getSize().height)) + { + setSize(MyGUI::IntSize(total_width+mPadding*2, total_height+mPadding*2)); + return; + } + + + int curY = 0; + for (unsigned int i = 0; i < count; ++i) + { + if (i==0) + curY += mPadding; + + MyGUI::Widget* w = getChildAt(i); + + bool hstretch = w->getUserString ("HStretch") == "true"; + int width = hstretch ? total_width : sizes[i].first.width; + + MyGUI::IntCoord widgetCoord; + widgetCoord.top = curY; + widgetCoord.left = mPadding + (getSize().width-mPadding*2 - width) / 2; + int height = sizes[i].second ? sizes[i].first.height + (getSize().height-mPadding*2 - total_height)/v_stretched_count + : sizes[i].first.height; + widgetCoord.height = height; + widgetCoord.width = width; + w->setCoord(widgetCoord); + curY += height; + + if (i != count-1) + curY += mSpacing; + } + } + + void VBox::setPropertyOverride(const std::string& _key, const std::string& _value) + { + Box::_setPropertyImpl (_key, _value); + } + + void VBox::setSize (const MyGUI::IntSize& _value) + { + MyGUI::Widget::setSize (_value); + align(); + } + + void VBox::setCoord (const MyGUI::IntCoord& _value) + { + MyGUI::Widget::setCoord (_value); + align(); + } + + MyGUI::IntSize VBox::getRequestedSize () + { + MyGUI::IntSize size(0,0); + for (unsigned int i = 0; i < getChildCount (); ++i) + { + AutoSizedWidget* w = dynamic_cast(getChildAt(i)); + if (w) + { + MyGUI::IntSize requested = w->getRequestedSize (); + size.width = std::max(size.width, requested.width); + size.height = size.height + requested.height; + if (i != getChildCount()-1) + size.height += mSpacing; + } + else + { + MyGUI::IntSize requested = getChildAt(i)->getSize (); + size.width = std::max(size.width, requested.width); + + if (getChildAt(i)->getUserString("VStretch") != "true") + size.height = size.height + requested.height; + + if (i != getChildCount()-1) + size.height += mSpacing; + } + size.height += mPadding*2; + size.width += mPadding*2; + } + return size; + } + + void VBox::onWidgetCreated(MyGUI::Widget* _widget) + { + align(); + } } } - -void VBox::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - Box::_setPropertyImpl (_key, _value); -} - -void VBox::setSize (const MyGUI::IntSize& _value) -{ - MyGUI::Widget::setSize (_value); - align(); -} - -void VBox::setCoord (const MyGUI::IntCoord& _value) -{ - MyGUI::Widget::setCoord (_value); - align(); -} - -MyGUI::IntSize VBox::getRequestedSize () -{ - MyGUI::IntSize size(0,0); - for (unsigned int i = 0; i < getChildCount (); ++i) - { - AutoSizedWidget* w = dynamic_cast(getChildAt(i)); - if (w) - { - MyGUI::IntSize requested = w->getRequestedSize (); - size.width = std::max(size.width, requested.width); - size.height = size.height + requested.height; - if (i != getChildCount()-1) - size.height += mSpacing; - } - else - { - MyGUI::IntSize requested = getChildAt(i)->getSize (); - size.width = std::max(size.width, requested.width); - - if (getChildAt(i)->getUserString("VStretch") != "true") - size.height = size.height + requested.height; - - if (i != getChildCount()-1) - size.height += mSpacing; - } - size.height += mPadding*2; - size.width += mPadding*2; - } - return size; -} - -void VBox::onWidgetCreated(MyGUI::Widget* _widget) -{ - align(); -} diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 154234bee5..2171beaffb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -39,1143 +39,1146 @@ #include "companionwindow.hpp" #include "inventorywindow.hpp" -using namespace MWGui; - -WindowManager::WindowManager( - const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, - const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, - Translation::Storage& translationDataStorage) - : mGuiManager(NULL) - , mRendering(ogre) - , mHud(NULL) - , mMap(NULL) - , mMenu(NULL) - , mStatsWindow(NULL) - , mToolTips(NULL) - , mMessageBoxManager(NULL) - , mConsole(NULL) - , mJournal(NULL) - , mDialogueWindow(NULL) - , mBookWindow(NULL) - , mScrollWindow(NULL) - , mCountDialog(NULL) - , mTradeWindow(NULL) - , mSpellBuyingWindow(NULL) - , mTravelWindow(NULL) - , mSettingsWindow(NULL) - , mConfirmationDialog(NULL) - , mAlchemyWindow(NULL) - , mSpellWindow(NULL) - , mLoadingScreen(NULL) - , mCharGen(NULL) - , mLevelupDialog(NULL) - , mWaitDialog(NULL) - , mSpellCreationDialog(NULL) - , mEnchantingDialog(NULL) - , mTrainingWindow(NULL) - , mMerchantRepair(NULL) - , mRepair(NULL) - , mSoulgemDialog(NULL) - , mCompanionWindow(NULL) - , mPlayerName() - , mPlayerRaceId() - , mPlayerAttributes() - , mPlayerMajorSkills() - , mPlayerMinorSkills() - , mPlayerSkillValues() - , mPlayerHealth() - , mPlayerMagicka() - , mPlayerFatigue() - , mGui(NULL) - , mGarbageDialogs() - , mShown(GW_ALL) - , mAllowed(newGame ? GW_None : GW_ALL) - , mRestAllowed(newGame ? false : true) - , mShowFPSLevel(fpsLevel) - , mFPS(0.0f) - , mTriangleCount(0) - , mBatchCount(0) - , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) - , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) - , mHudEnabled(true) - , mTranslationDataStorage (translationDataStorage) +namespace MWGui { - // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); - mGui = mGuiManager->getGui(); - //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"); - 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"); - - MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); - MyGUI::ResourceManager::getInstance().load("core.xml"); - - MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - - // Get size info from the Gui object - assert(mGui); - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - - MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); - dragAndDropWidget->setVisible(false); - - mDragAndDrop = new DragAndDrop(); - mDragAndDrop->mIsOnDragAndDrop = false; - mDragAndDrop->mDraggedWidget = 0; - mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - - mMenu = new MainMenu(w,h); - mMap = new MapWindow(cacheDir); - mStatsWindow = new StatsWindow(); - mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(); - mMessageBoxManager = new MessageBoxManager(); - mInventoryWindow = new InventoryWindow(mDragAndDrop); - mTradeWindow = new TradeWindow(); - mSpellBuyingWindow = new SpellBuyingWindow(); - mTravelWindow = new TravelWindow(); - mDialogueWindow = new DialogueWindow(); - mContainerWindow = new ContainerWindow(mDragAndDrop); - mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); - mToolTips = new ToolTips(); - mScrollWindow = new ScrollWindow(); - mBookWindow = new BookWindow(); - mCountDialog = new CountDialog(); - mSettingsWindow = new SettingsWindow(); - mConfirmationDialog = new ConfirmationDialog(); - mAlchemyWindow = new AlchemyWindow(); - mSpellWindow = new SpellWindow(); - mQuickKeysMenu = new QuickKeysMenu(); - mLevelupDialog = new LevelupDialog(); - mWaitDialog = new WaitDialog(); - mSpellCreationDialog = new SpellCreationDialog(); - mEnchantingDialog = new EnchantingDialog(); - mTrainingWindow = new TrainingWindow(); - mMerchantRepair = new MerchantRepair(); - mRepair = new Repair(); - mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); - mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); - - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); - mLoadingScreen->onResChange (w,h); - - mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); - - mCursor = new Cursor(); - - mHud->setVisible(mHudEnabled); - - mCharGen = new CharacterCreation(); - - // Setup player stats - for (int i = 0; i < ESM::Attribute::Length; ++i) + WindowManager::WindowManager( + const Compiler::Extensions& extensions, int fpsLevel, bool newGame, OEngine::Render::OgreRenderer *ogre, + const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, + Translation::Storage& translationDataStorage) + : mGuiManager(NULL) + , mRendering(ogre) + , mHud(NULL) + , mMap(NULL) + , mMenu(NULL) + , mStatsWindow(NULL) + , mToolTips(NULL) + , mMessageBoxManager(NULL) + , mConsole(NULL) + , mJournal(NULL) + , mDialogueWindow(NULL) + , mBookWindow(NULL) + , mScrollWindow(NULL) + , mCountDialog(NULL) + , mTradeWindow(NULL) + , mSpellBuyingWindow(NULL) + , mTravelWindow(NULL) + , mSettingsWindow(NULL) + , mConfirmationDialog(NULL) + , mAlchemyWindow(NULL) + , mSpellWindow(NULL) + , mLoadingScreen(NULL) + , mCharGen(NULL) + , mLevelupDialog(NULL) + , mWaitDialog(NULL) + , mSpellCreationDialog(NULL) + , mEnchantingDialog(NULL) + , mTrainingWindow(NULL) + , mMerchantRepair(NULL) + , mRepair(NULL) + , mSoulgemDialog(NULL) + , mCompanionWindow(NULL) + , mPlayerName() + , mPlayerRaceId() + , mPlayerAttributes() + , mPlayerMajorSkills() + , mPlayerMinorSkills() + , mPlayerSkillValues() + , mPlayerHealth() + , mPlayerMagicka() + , mPlayerFatigue() + , mGui(NULL) + , mGarbageDialogs() + , mShown(GW_ALL) + , mAllowed(newGame ? GW_None : GW_ALL) + , mRestAllowed(newGame ? false : true) + , mShowFPSLevel(fpsLevel) + , mFPS(0.0f) + , mTriangleCount(0) + , mBatchCount(0) + , mCrosshairEnabled(Settings::Manager::getBool ("crosshair", "HUD")) + , mSubtitlesEnabled(Settings::Manager::getBool ("subtitles", "GUI")) + , mHudEnabled(true) + , mTranslationDataStorage (translationDataStorage) { - mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); - } + // Set up the GUI system + mGuiManager = new OEngine::GUI::MyGUIManager(mRendering->getWindow(), mRendering->getScene(), false, logpath); + mGui = mGuiManager->getGui(); - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); - } + //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"); + 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"); - unsetSelectedSpell(); - unsetSelectedWeapon(); + MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); + MyGUI::ResourceManager::getInstance().load("core.xml"); - if (newGame) - disallowAll (); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - // Set up visibility - updateVisible(); -} + // Get size info from the Gui object + assert(mGui); + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + int h = MyGUI::RenderManager::getInstance().getViewSize().height; -WindowManager::~WindowManager() -{ - delete mConsole; - delete mMessageBoxManager; - delete mHud; - delete mMap; - delete mMenu; - delete mStatsWindow; - delete mJournal; - delete mDialogueWindow; - delete mContainerWindow; - delete mInventoryWindow; - delete mToolTips; - delete mCharGen; - delete mDragAndDrop; - delete mBookWindow; - delete mScrollWindow; - delete mTradeWindow; - delete mSpellBuyingWindow; - delete mTravelWindow; - delete mSettingsWindow; - delete mConfirmationDialog; - delete mAlchemyWindow; - delete mSpellWindow; - delete mLoadingScreen; - delete mLevelupDialog; - delete mWaitDialog; - delete mSpellCreationDialog; - delete mEnchantingDialog; - delete mTrainingWindow; - delete mCountDialog; - delete mQuickKeysMenu; - delete mMerchantRepair; - delete mRepair; - delete mSoulgemDialog; - delete mCursor; + MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); + dragAndDropWidget->setVisible(false); - cleanupGarbage(); + mDragAndDrop = new DragAndDrop(); + mDragAndDrop->mIsOnDragAndDrop = false; + mDragAndDrop->mDraggedWidget = 0; + mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; - delete mGuiManager; -} + mMenu = new MainMenu(w,h); + mMap = new MapWindow(cacheDir); + mStatsWindow = new StatsWindow(); + mConsole = new Console(w,h, consoleOnlyScripts); + mJournal = new JournalWindow(); + mMessageBoxManager = new MessageBoxManager(); + mInventoryWindow = new InventoryWindow(mDragAndDrop); + mTradeWindow = new TradeWindow(); + mSpellBuyingWindow = new SpellBuyingWindow(); + mTravelWindow = new TravelWindow(); + mDialogueWindow = new DialogueWindow(); + mContainerWindow = new ContainerWindow(mDragAndDrop); + mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); + mToolTips = new ToolTips(); + mScrollWindow = new ScrollWindow(); + mBookWindow = new BookWindow(); + mCountDialog = new CountDialog(); + mSettingsWindow = new SettingsWindow(); + mConfirmationDialog = new ConfirmationDialog(); + mAlchemyWindow = new AlchemyWindow(); + mSpellWindow = new SpellWindow(); + mQuickKeysMenu = new QuickKeysMenu(); + mLevelupDialog = new LevelupDialog(); + mWaitDialog = new WaitDialog(); + mSpellCreationDialog = new SpellCreationDialog(); + mEnchantingDialog = new EnchantingDialog(); + mTrainingWindow = new TrainingWindow(); + mMerchantRepair = new MerchantRepair(); + mRepair = new Repair(); + mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); + mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); -void WindowManager::cleanupGarbage() -{ - // Delete any dialogs which are no longer in use - if (!mGarbageDialogs.empty()) - { - for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); + mLoadingScreen->onResChange (w,h); + + mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Windows",""); + + mCursor = new Cursor(); + + mHud->setVisible(mHudEnabled); + + mCharGen = new CharacterCreation(); + + // Setup player stats + for (int i = 0; i < ESM::Attribute::Length; ++i) { - delete *it; + mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::Stat())); } - mGarbageDialogs.clear(); - } -} -void WindowManager::update() -{ - cleanupGarbage(); - - mHud->setFPS(mFPS); - mHud->setTriangleCount(mTriangleCount); - mHud->setBatchCount(mBatchCount); - - mHud->update(); - - mCursor->update(); -} - -void WindowManager::updateVisible() -{ - // Start out by hiding everything except the HUD - mMap->setVisible(false); - mMenu->setVisible(false); - mStatsWindow->setVisible(false); - mConsole->disable(); - mJournal->setVisible(false); - mDialogueWindow->setVisible(false); - mContainerWindow->setVisible(false); - mInventoryWindow->setVisible(false); - mScrollWindow->setVisible(false); - mBookWindow->setVisible(false); - mTradeWindow->setVisible(false); - mSpellBuyingWindow->setVisible(false); - mTravelWindow->setVisible(false); - mSettingsWindow->setVisible(false); - mAlchemyWindow->setVisible(false); - mSpellWindow->setVisible(false); - mQuickKeysMenu->setVisible(false); - mLevelupDialog->setVisible(false); - mWaitDialog->setVisible(false); - mSpellCreationDialog->setVisible(false); - mEnchantingDialog->setVisible(false); - mTrainingWindow->setVisible(false); - mMerchantRepair->setVisible(false); - mRepair->setVisible(false); - mCompanionWindow->setVisible(false); - - mHud->setVisible(mHudEnabled); - - bool gameMode = !isGuiMode(); - - mInputBlocker->setVisible (gameMode); - - if (gameMode) - mToolTips->enterGameMode(); - else - mToolTips->enterGuiMode(); - - if (gameMode) - MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); - - setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); - setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); - setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); - setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - - // If in game mode, show only the pinned windows - if (gameMode) - { - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - - return; - } - - GuiMode mode = mGuiModes.back(); - - switch(mode) { - case GM_QuickKeysMenu: - mQuickKeysMenu->setVisible (true); - break; - case GM_MainMenu: - mMenu->setVisible(true); - break; - case GM_Settings: - mSettingsWindow->setVisible(true); - break; - case GM_Console: - // Show the pinned windows - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - - mConsole->enable(); - break; - case GM_Scroll: - mScrollWindow->setVisible(true); - break; - case GM_Book: - mBookWindow->setVisible(true); - break; - case GM_Alchemy: - mAlchemyWindow->setVisible(true); - break; - case GM_Rest: - mWaitDialog->setVisible(true); - break; - case GM_RestBed: - mWaitDialog->setVisible(true); - mWaitDialog->bedActivated(); - break; - case GM_Levelup: - mLevelupDialog->setVisible(true); - break; - case GM_Name: - case GM_Race: - case GM_Class: - case GM_ClassPick: - case GM_ClassCreate: - case GM_Birth: - case GM_ClassGenerate: - case GM_Review: - mCharGen->spawnDialog(mode); - break; - case GM_Inventory: + for (int i = 0; i < ESM::Skill::Length; ++i) { - // First, compute the effective set of windows to show. - // This is controlled both by what windows the - // user has opened/closed (the 'shown' variable) and by what - // windows we are allowed to show (the 'allowed' var.) - int eff = mShown & mAllowed; - - // Show the windows we want - mMap ->setVisible(eff & GW_Map); - mStatsWindow ->setVisible(eff & GW_Stats); - mInventoryWindow->setVisible(eff & GW_Inventory); - mSpellWindow ->setVisible(eff & GW_Magic); - break; + mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::Stat())); } - case GM_Container: - mContainerWindow->setVisible(true); - mInventoryWindow->setVisible(true); - break; - case GM_Companion: - mCompanionWindow->setVisible(true); - mInventoryWindow->setVisible(true); - break; - case GM_Dialogue: - mDialogueWindow->setVisible(true); - break; - case GM_Barter: - mInventoryWindow->setVisible(true); - mTradeWindow->setVisible(true); - break; - case GM_SpellBuying: - mSpellBuyingWindow->setVisible(true); - break; - case GM_Travel: - mTravelWindow->setVisible(true); - break; - case GM_SpellCreation: - mSpellCreationDialog->setVisible(true); - break; - case GM_Enchanting: - mEnchantingDialog->setVisible(true); - break; - case GM_Training: - mTrainingWindow->setVisible(true); - break; - case GM_MerchantRepair: - mMerchantRepair->setVisible(true); - break; - case GM_Repair: - mRepair->setVisible(true); - break; - case GM_Journal: - mJournal->setVisible(true); - break; - case GM_LoadingWallpaper: - mHud->setVisible(false); - mCursor->setVisible(false); - break; - case GM_Loading: - // Show the pinned windows - mMap->setVisible(mMap->pinned()); - mStatsWindow->setVisible(mStatsWindow->pinned()); - mInventoryWindow->setVisible(mInventoryWindow->pinned()); - mSpellWindow->setVisible(mSpellWindow->pinned()); - mCursor->setVisible(false); - break; - case GM_Video: - mCursor->setVisible(false); - mHud->setVisible(false); - break; - default: - // Unsupported mode, switch back to game - break; - } -} + unsetSelectedSpell(); + unsetSelectedWeapon(); -void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) -{ - mStatsWindow->setValue (id, value); - mCharGen->setValue(id, value); + if (newGame) + disallowAll (); - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8" - }; - static ESM::Attribute::AttributeID attributes[] = - { - ESM::Attribute::Strength, - ESM::Attribute::Intelligence, - ESM::Attribute::Willpower, - ESM::Attribute::Agility, - ESM::Attribute::Speed, - ESM::Attribute::Endurance, - ESM::Attribute::Personality, - ESM::Attribute::Luck - }; - for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) - { - if (id != ids[i]) - continue; - mPlayerAttributes[attributes[i]] = value; - break; - } -} - - -void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) -{ - /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we - /// allow custom skills. - mStatsWindow->setValue(static_cast (parSkill), value); - mCharGen->setValue(static_cast (parSkill), value); - mPlayerSkillValues[parSkill] = value; -} - -void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) -{ - mStatsWindow->setValue (id, value); - mHud->setValue (id, value); - mCharGen->setValue(id, value); - if (id == "HBar") - { - mPlayerHealth = value; - mCharGen->setPlayerHealth (value); - } - else if (id == "MBar") - { - mPlayerMagicka = value; - mCharGen->setPlayerMagicka (value); - } - else if (id == "FBar") - { - mPlayerFatigue = value; - mCharGen->setPlayerFatigue (value); - } -} - -#if 0 -MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) -{ - if(id == "HBar") - return layerHealth; - else if (id == "MBar") - return mPlayerMagicka; - else if (id == "FBar") - return mPlayerFatigue; -} -#endif - -void WindowManager::setValue (const std::string& id, const std::string& value) -{ - mStatsWindow->setValue (id, value); - if (id=="name") - mPlayerName = value; - else if (id=="race") - mPlayerRaceId = value; -} - -void WindowManager::setValue (const std::string& id, int value) -{ - mStatsWindow->setValue (id, value); -} - -void WindowManager::setPlayerClass (const ESM::Class &class_) -{ - mStatsWindow->setValue("class", class_.mName); -} - -void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) -{ - mStatsWindow->configureSkills (major, minor); - mCharGen->configureSkills(major, minor); - mPlayerMajorSkills = major; - mPlayerMinorSkills = minor; -} - -void WindowManager::setReputation (int reputation) -{ - mStatsWindow->setReputation (reputation); -} - -void WindowManager::setBounty (int bounty) -{ - mStatsWindow->setBounty (bounty); -} - -void WindowManager::updateSkillArea() -{ - mStatsWindow->updateSkillArea(); -} - -void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) -{ - if (!dialog) - return; - dialog->setVisible(false); - mGarbageDialogs.push_back(dialog); -} - -void WindowManager::messageBox (const std::string& message, const std::vector& buttons) -{ - if(buttons.empty()){ - /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ - if(!mGuiModes.empty() && mGuiModes.back() == GM_Dialogue) - mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); - else - mMessageBoxManager->createMessageBox(message); + // Set up visibility + updateVisible(); } - else + WindowManager::~WindowManager() { - mMessageBoxManager->createInteractiveMessageBox(message, buttons); - MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); + delete mConsole; + delete mMessageBoxManager; + delete mHud; + delete mMap; + delete mMenu; + delete mStatsWindow; + delete mJournal; + delete mDialogueWindow; + delete mContainerWindow; + delete mInventoryWindow; + delete mToolTips; + delete mCharGen; + delete mDragAndDrop; + delete mBookWindow; + delete mScrollWindow; + delete mTradeWindow; + delete mSpellBuyingWindow; + delete mTravelWindow; + delete mSettingsWindow; + delete mConfirmationDialog; + delete mAlchemyWindow; + delete mSpellWindow; + delete mLoadingScreen; + delete mLevelupDialog; + delete mWaitDialog; + delete mSpellCreationDialog; + delete mEnchantingDialog; + delete mTrainingWindow; + delete mCountDialog; + delete mQuickKeysMenu; + delete mMerchantRepair; + delete mRepair; + delete mSoulgemDialog; + delete mCursor; + + cleanupGarbage(); + + delete mGuiManager; } -} -void WindowManager::enterPressed () -{ - mMessageBoxManager->enterPressed(); -} - -int WindowManager::readPressedButton () -{ - return mMessageBoxManager->readPressedButton(); -} - -std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) -{ - const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().search(id); - - if (setting && setting->mValue.getType()==ESM::VT_String) - return setting->mValue.getString(); - - return default_; -} - -void WindowManager::onDialogueWindowBye() -{ - if (mDialogueWindow) + void WindowManager::cleanupGarbage() { - //FIXME set some state and stuff? - //removeDialog(dialogueWindow); + // Delete any dialogs which are no longer in use + if (!mGarbageDialogs.empty()) + { + for (std::vector::iterator it = mGarbageDialogs.begin(); it != mGarbageDialogs.end(); ++it) + { + delete *it; + } + mGarbageDialogs.clear(); + } + } + + void WindowManager::update() + { + cleanupGarbage(); + + mHud->setFPS(mFPS); + mHud->setTriangleCount(mTriangleCount); + mHud->setBatchCount(mBatchCount); + + mHud->update(); + + mCursor->update(); + } + + void WindowManager::updateVisible() + { + // Start out by hiding everything except the HUD + mMap->setVisible(false); + mMenu->setVisible(false); + mStatsWindow->setVisible(false); + mConsole->disable(); + mJournal->setVisible(false); mDialogueWindow->setVisible(false); - } - removeGuiMode(GM_Dialogue); -} + mContainerWindow->setVisible(false); + mInventoryWindow->setVisible(false); + mScrollWindow->setVisible(false); + mBookWindow->setVisible(false); + mTradeWindow->setVisible(false); + mSpellBuyingWindow->setVisible(false); + mTravelWindow->setVisible(false); + mSettingsWindow->setVisible(false); + mAlchemyWindow->setVisible(false); + mSpellWindow->setVisible(false); + mQuickKeysMenu->setVisible(false); + mLevelupDialog->setVisible(false); + mWaitDialog->setVisible(false); + mSpellCreationDialog->setVisible(false); + mEnchantingDialog->setVisible(false); + mTrainingWindow->setVisible(false); + mMerchantRepair->setVisible(false); + mRepair->setVisible(false); + mCompanionWindow->setVisible(false); -void WindowManager::onFrame (float frameDuration) -{ - mMessageBoxManager->onFrame(frameDuration); + mHud->setVisible(mHudEnabled); - mToolTips->onFrame(frameDuration); + bool gameMode = !isGuiMode(); - if (mDragAndDrop->mIsOnDragAndDrop) - { - assert(mDragAndDrop->mDraggedWidget); - mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); - } + mInputBlocker->setVisible (gameMode); - mDialogueWindow->onFrame(); + if (gameMode) + mToolTips->enterGameMode(); + else + mToolTips->enterGuiMode(); - mInventoryWindow->onFrame(); + if (gameMode) + MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); - mStatsWindow->onFrame(); + setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); + setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); + setSpellVisibility((mAllowed & GW_Magic) && !mSpellWindow->pinned()); + setHMSVisibility((mAllowed & GW_Stats) && !mStatsWindow->pinned()); - mWaitDialog->onFrame(frameDuration); - - mHud->onFrame(frameDuration); - - mTrainingWindow->onFrame (frameDuration); - mTradeWindow->onFrame(frameDuration); - - mTrainingWindow->checkReferenceAvailable(); - mDialogueWindow->checkReferenceAvailable(); - mTradeWindow->checkReferenceAvailable(); - mSpellBuyingWindow->checkReferenceAvailable(); - mSpellCreationDialog->checkReferenceAvailable(); - mEnchantingDialog->checkReferenceAvailable(); - mContainerWindow->checkReferenceAvailable(); - mCompanionWindow->checkReferenceAvailable(); - mConsole->checkReferenceAvailable(); -} - -void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) -{ - if (cell->mCell->isExterior()) - { - std::string name; - if (cell->mCell->mName != "") + // If in game mode, show only the pinned windows + if (gameMode) { - name = cell->mCell->mName; - mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + return; } + + GuiMode mode = mGuiModes.back(); + + switch(mode) { + case GM_QuickKeysMenu: + mQuickKeysMenu->setVisible (true); + break; + case GM_MainMenu: + mMenu->setVisible(true); + break; + case GM_Settings: + mSettingsWindow->setVisible(true); + break; + case GM_Console: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + mConsole->enable(); + break; + case GM_Scroll: + mScrollWindow->setVisible(true); + break; + case GM_Book: + mBookWindow->setVisible(true); + break; + case GM_Alchemy: + mAlchemyWindow->setVisible(true); + break; + case GM_Rest: + mWaitDialog->setVisible(true); + break; + case GM_RestBed: + mWaitDialog->setVisible(true); + mWaitDialog->bedActivated(); + break; + case GM_Levelup: + mLevelupDialog->setVisible(true); + break; + case GM_Name: + case GM_Race: + case GM_Class: + case GM_ClassPick: + case GM_ClassCreate: + case GM_Birth: + case GM_ClassGenerate: + case GM_Review: + mCharGen->spawnDialog(mode); + break; + case GM_Inventory: + { + // First, compute the effective set of windows to show. + // This is controlled both by what windows the + // user has opened/closed (the 'shown' variable) and by what + // windows we are allowed to show (the 'allowed' var.) + int eff = mShown & mAllowed; + + // Show the windows we want + mMap ->setVisible(eff & GW_Map); + mStatsWindow ->setVisible(eff & GW_Stats); + mInventoryWindow->setVisible(eff & GW_Inventory); + mSpellWindow ->setVisible(eff & GW_Magic); + break; + } + case GM_Container: + mContainerWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; + case GM_Companion: + mCompanionWindow->setVisible(true); + mInventoryWindow->setVisible(true); + break; + case GM_Dialogue: + mDialogueWindow->setVisible(true); + break; + case GM_Barter: + mInventoryWindow->setVisible(true); + mTradeWindow->setVisible(true); + break; + case GM_SpellBuying: + mSpellBuyingWindow->setVisible(true); + break; + case GM_Travel: + mTravelWindow->setVisible(true); + break; + case GM_SpellCreation: + mSpellCreationDialog->setVisible(true); + break; + case GM_Enchanting: + mEnchantingDialog->setVisible(true); + break; + case GM_Training: + mTrainingWindow->setVisible(true); + break; + case GM_MerchantRepair: + mMerchantRepair->setVisible(true); + break; + case GM_Repair: + mRepair->setVisible(true); + break; + case GM_Journal: + mJournal->setVisible(true); + break; + case GM_LoadingWallpaper: + mHud->setVisible(false); + mCursor->setVisible(false); + break; + case GM_Loading: + // Show the pinned windows + mMap->setVisible(mMap->pinned()); + mStatsWindow->setVisible(mStatsWindow->pinned()); + mInventoryWindow->setVisible(mInventoryWindow->pinned()); + mSpellWindow->setVisible(mSpellWindow->pinned()); + + mCursor->setVisible(false); + break; + case GM_Video: + mCursor->setVisible(false); + mHud->setVisible(false); + break; + default: + // Unsupported mode, switch back to game + break; + } + } + + void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) + { + mStatsWindow->setValue (id, value); + mCharGen->setValue(id, value); + + static const char *ids[] = + { + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", + "AttribVal6", "AttribVal7", "AttribVal8" + }; + static ESM::Attribute::AttributeID attributes[] = + { + ESM::Attribute::Strength, + ESM::Attribute::Intelligence, + ESM::Attribute::Willpower, + ESM::Attribute::Agility, + ESM::Attribute::Speed, + ESM::Attribute::Endurance, + ESM::Attribute::Personality, + ESM::Attribute::Luck + }; + for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) + { + if (id != ids[i]) + continue; + mPlayerAttributes[attributes[i]] = value; + break; + } + } + + + void WindowManager::setValue (int parSkill, const MWMechanics::Stat& value) + { + /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we + /// allow custom skills. + mStatsWindow->setValue(static_cast (parSkill), value); + mCharGen->setValue(static_cast (parSkill), value); + mPlayerSkillValues[parSkill] = value; + } + + void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) + { + mStatsWindow->setValue (id, value); + mHud->setValue (id, value); + mCharGen->setValue(id, value); + if (id == "HBar") + { + mPlayerHealth = value; + mCharGen->setPlayerHealth (value); + } + else if (id == "MBar") + { + mPlayerMagicka = value; + mCharGen->setPlayerMagicka (value); + } + else if (id == "FBar") + { + mPlayerFatigue = value; + mCharGen->setPlayerFatigue (value); + } + } + + #if 0 + MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) + { + if(id == "HBar") + return layerHealth; + else if (id == "MBar") + return mPlayerMagicka; + else if (id == "FBar") + return mPlayerFatigue; + } + #endif + + void WindowManager::setValue (const std::string& id, const std::string& value) + { + mStatsWindow->setValue (id, value); + if (id=="name") + mPlayerName = value; + else if (id=="race") + mPlayerRaceId = value; + } + + void WindowManager::setValue (const std::string& id, int value) + { + mStatsWindow->setValue (id, value); + } + + void WindowManager::setPlayerClass (const ESM::Class &class_) + { + mStatsWindow->setValue("class", class_.mName); + } + + void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) + { + mStatsWindow->configureSkills (major, minor); + mCharGen->configureSkills(major, minor); + mPlayerMajorSkills = major; + mPlayerMinorSkills = minor; + } + + void WindowManager::setReputation (int reputation) + { + mStatsWindow->setReputation (reputation); + } + + void WindowManager::setBounty (int bounty) + { + mStatsWindow->setBounty (bounty); + } + + void WindowManager::updateSkillArea() + { + mStatsWindow->updateSkillArea(); + } + + void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) + { + if (!dialog) + return; + dialog->setVisible(false); + mGarbageDialogs.push_back(dialog); + } + + void WindowManager::messageBox (const std::string& message, const std::vector& buttons) + { + if(buttons.empty()){ + /* If there are no buttons, and there is a dialogue window open, messagebox goes to the dialogue window */ + if(!mGuiModes.empty() && mGuiModes.back() == GM_Dialogue) + mDialogueWindow->addMessageBox(MyGUI::LanguageManager::getInstance().replaceTags(message)); + else + mMessageBoxManager->createMessageBox(message); + } + else { - const ESM::Region* region = - MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); - if (region) - name = region->mName; - else - name = getGameSettingString("sDefaultCellname", "Wilderness"); + mMessageBoxManager->createInteractiveMessageBox(message, buttons); + MWBase::Environment::get().getInputManager()->changeInputMode(isGuiMode()); } - - mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); - - mMap->setCellName( name ); - mHud->setCellName( name ); - - mMap->setCellPrefix("Cell"); - mHud->setCellPrefix("Cell"); - mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); - mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); } - else + + void WindowManager::enterPressed () { - mMap->setCellName( cell->mCell->mName ); - mHud->setCellName( cell->mCell->mName ); - mMap->setCellPrefix( cell->mCell->mName ); - mHud->setCellPrefix( cell->mCell->mName ); + mMessageBoxManager->enterPressed(); } -} - -void WindowManager::setInteriorMapTexture(const int x, const int y) -{ - mMap->setActiveCell(x,y, true); - mHud->setActiveCell(x,y, true); -} - -void WindowManager::setPlayerPos(const float x, const float y) -{ - mMap->setPlayerPos(x,y); - mHud->setPlayerPos(x,y); -} - -void WindowManager::setPlayerDir(const float x, const float y) -{ - mMap->setPlayerDir(x,y); - mHud->setPlayerDir(x,y); -} - -void WindowManager::setHMSVisibility(bool visible) -{ - mHud->setHmsVisible (visible); -} - -void WindowManager::setMinimapVisibility(bool visible) -{ - mHud->setMinimapVisible (visible); -} - -void WindowManager::toggleFogOfWar() -{ - mMap->toggleFogOfWar(); - mHud->toggleFogOfWar(); -} - -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(); -} - -bool WindowManager::getFullHelp() const -{ - return mToolTips->getFullHelp(); -} - -void WindowManager::setWeaponVisibility(bool visible) -{ - mHud->setWeapVisible (visible); -} - -void WindowManager::setSpellVisibility(bool visible) -{ - mHud->setSpellVisible (visible); - mHud->setEffectVisible (visible); -} - -void WindowManager::setMouseVisible(bool visible) -{ - mCursor->setVisible(visible); -} - -void WindowManager::setDragDrop(bool dragDrop) -{ - mToolTips->setEnabled(!dragDrop); - MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); -} - -void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) -{ - std::string tag(_tag); - - std::string tokenToFind = "sCell="; - size_t tokenLength = tokenToFind.length(); - - if (tag.substr(0, tokenLength) == tokenToFind) + int WindowManager::readPressedButton () { - _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + return mMessageBoxManager->readPressedButton(); } - else + + std::string WindowManager::getGameSettingString(const std::string &id, const std::string &default_) { const ESM::GameSetting *setting = - MWBase::Environment::get().getWorld()->getStore().get().find(tag); + MWBase::Environment::get().getWorld()->getStore().get().search(id); if (setting && setting->mValue.getType()==ESM::VT_String) - _result = setting->mValue.getString(); - else - _result = tag; + return setting->mValue.getString(); + + return default_; } -} -void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) -{ - mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); - mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); - - bool changeRes = false; - bool windowRecreated = false; - for (Settings::CategorySettingVector::const_iterator it = changed.begin(); - it != changed.end(); ++it) + void WindowManager::onDialogueWindowBye() { - if (it->first == "Video" && ( - it->second == "resolution x" - || it->second == "resolution y")) + if (mDialogueWindow) { - changeRes = true; + //FIXME set some state and stuff? + //removeDialog(dialogueWindow); + mDialogueWindow->setVisible(false); } - else if (it->first == "Video" && it->second == "vsync") - windowRecreated = true; - else if (it->first == "HUD" && it->second == "crosshair") - mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); - else if (it->first == "GUI" && it->second == "subtitles") - mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + removeGuiMode(GM_Dialogue); } - if (changeRes) + void WindowManager::onFrame (float frameDuration) { - int x = Settings::Manager::getInt("resolution x", "Video"); - int y = Settings::Manager::getInt("resolution y", "Video"); - mHud->onResChange(x, y); - mConsole->onResChange(x, y); - mMenu->onResChange(x, y); - mSettingsWindow->center(); - mAlchemyWindow->center(); - mScrollWindow->center(); - mBookWindow->center(); - mQuickKeysMenu->center(); - mSpellBuyingWindow->center(); - mLoadingScreen->onResChange (x,y); - mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); - mInputBlocker->setSize(MyGUI::IntSize(x,y)); - } - if (windowRecreated) - { - mGuiManager->updateWindow (mRendering->getWindow ()); - mLoadingScreen->updateWindow (mRendering->getWindow ()); - } -} + mMessageBoxManager->onFrame(frameDuration); -void WindowManager::pushGuiMode(GuiMode mode) -{ - if (mode==GM_Inventory && mAllowed==GW_None) - return; + mToolTips->onFrame(frameDuration); + if (mDragAndDrop->mIsOnDragAndDrop) + { + assert(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + } - // If this mode already exists somewhere in the stack, just bring it to the front. - if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) - { - mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + mDialogueWindow->onFrame(); + + mInventoryWindow->onFrame(); + + mStatsWindow->onFrame(); + + mWaitDialog->onFrame(frameDuration); + + mHud->onFrame(frameDuration); + + mTrainingWindow->onFrame (frameDuration); + mTradeWindow->onFrame(frameDuration); + + mTrainingWindow->checkReferenceAvailable(); + mDialogueWindow->checkReferenceAvailable(); + mTradeWindow->checkReferenceAvailable(); + mSpellBuyingWindow->checkReferenceAvailable(); + mSpellCreationDialog->checkReferenceAvailable(); + mEnchantingDialog->checkReferenceAvailable(); + mContainerWindow->checkReferenceAvailable(); + mCompanionWindow->checkReferenceAvailable(); + mConsole->checkReferenceAvailable(); } - mGuiModes.push_back(mode); - - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::popGuiMode() -{ - if (!mGuiModes.empty()) - mGuiModes.pop_back(); - - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::removeGuiMode(GuiMode mode) -{ - std::vector::iterator it = mGuiModes.begin(); - while (it != mGuiModes.end()) + void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) { - if (*it == mode) - it = mGuiModes.erase(it); + if (cell->mCell->isExterior()) + { + std::string name; + if (cell->mCell->mName != "") + { + name = cell->mCell->mName; + mMap->addVisitedLocation ("#{sCell=" + name + "}", cell->mCell->getGridX (), cell->mCell->getGridY ()); + } + else + { + const ESM::Region* region = + MWBase::Environment::get().getWorld()->getStore().get().search(cell->mCell->mRegion); + if (region) + name = region->mName; + else + name = getGameSettingString("sDefaultCellname", "Wilderness"); + } + + mMap->cellExplored(cell->mCell->getGridX(), cell->mCell->getGridY()); + + mMap->setCellName( name ); + mHud->setCellName( name ); + + mMap->setCellPrefix("Cell"); + mHud->setCellPrefix("Cell"); + mMap->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + mHud->setActiveCell( cell->mCell->getGridX(), cell->mCell->getGridY() ); + } else - ++it; + { + mMap->setCellName( cell->mCell->mName ); + mHud->setCellName( cell->mCell->mName ); + mMap->setCellPrefix( cell->mCell->mName ); + mHud->setCellPrefix( cell->mCell->mName ); + } + } - bool gameMode = !isGuiMode(); - MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); - - updateVisible(); -} - -void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) -{ - mHud->setSelectedSpell(spellId, successChancePercent); - - const ESM::Spell* spell = - MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - - mSpellWindow->setTitle(spell->mName); -} - -void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) -{ - const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() - .find(MWWorld::Class::get(item).getEnchantment(item)); - - int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; - mHud->setSelectedEnchantItem(item, chargePercent); - mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); -} - -void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) -{ - int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; - mHud->setSelectedWeapon(item, durabilityPercent); - mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); -} - -void WindowManager::unsetSelectedSpell() -{ - mHud->unsetSelectedSpell(); - mSpellWindow->setTitle("#{sNone}"); -} - -void WindowManager::unsetSelectedWeapon() -{ - mHud->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 mHud->getWorldMouseOver(); -} - -void WindowManager::executeInConsole (const std::string& path) -{ - mConsole->executeFile (path); -} - -void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) -{ - mFPS = fps; - mTriangleCount = triangleCount; - mBatchCount = batchCount; -} - -MyGUI::Gui* WindowManager::getGui() const { return mGui; } - -MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } -MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } -MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } -MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } -MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } -MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } -MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } -MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } -MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } -MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } -MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } -MWGui::Console* WindowManager::getConsole() { return mConsole; } - -bool WindowManager::isAllowed (GuiWindow wnd) const -{ - return mAllowed & wnd; -} - -void WindowManager::allow (GuiWindow wnd) -{ - mAllowed = (GuiWindow)(mAllowed | wnd); - - if (wnd & GW_Inventory) + void WindowManager::setInteriorMapTexture(const int x, const int y) { - mBookWindow->setInventoryAllowed (true); - mScrollWindow->setInventoryAllowed (true); + mMap->setActiveCell(x,y, true); + mHud->setActiveCell(x,y, true); + } + + void WindowManager::setPlayerPos(const float x, const float y) + { + mMap->setPlayerPos(x,y); + mHud->setPlayerPos(x,y); + } + + void WindowManager::setPlayerDir(const float x, const float y) + { + mMap->setPlayerDir(x,y); + mHud->setPlayerDir(x,y); + } + + void WindowManager::setHMSVisibility(bool visible) + { + mHud->setHmsVisible (visible); + } + + void WindowManager::setMinimapVisibility(bool visible) + { + mHud->setMinimapVisible (visible); + } + + void WindowManager::toggleFogOfWar() + { + mMap->toggleFogOfWar(); + mHud->toggleFogOfWar(); + } + + 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(); + } + + bool WindowManager::getFullHelp() const + { + return mToolTips->getFullHelp(); + } + + void WindowManager::setWeaponVisibility(bool visible) + { + mHud->setWeapVisible (visible); + } + + void WindowManager::setSpellVisibility(bool visible) + { + mHud->setSpellVisible (visible); + mHud->setEffectVisible (visible); + } + + void WindowManager::setMouseVisible(bool visible) + { + mCursor->setVisible(visible); + } + + void WindowManager::setDragDrop(bool dragDrop) + { + mToolTips->setEnabled(!dragDrop); + MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); + } + + void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) + { + std::string tag(_tag); + + std::string tokenToFind = "sCell="; + size_t tokenLength = tokenToFind.length(); + + if (tag.substr(0, tokenLength) == tokenToFind) + { + _result = mTranslationDataStorage.translateCellName(tag.substr(tokenLength)); + } + else + { + const ESM::GameSetting *setting = + MWBase::Environment::get().getWorld()->getStore().get().find(tag); + + if (setting && setting->mValue.getType()==ESM::VT_String) + _result = setting->mValue.getString(); + else + _result = tag; + } + } + + void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed) + { + mHud->setFpsLevel(Settings::Manager::getInt("fps", "HUD")); + mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI")); + + bool changeRes = false; + bool windowRecreated = 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; + } + else if (it->first == "Video" && it->second == "vsync") + windowRecreated = true; + else if (it->first == "HUD" && it->second == "crosshair") + mCrosshairEnabled = Settings::Manager::getBool ("crosshair", "HUD"); + else if (it->first == "GUI" && it->second == "subtitles") + mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI"); + } + + if (changeRes) + { + int x = Settings::Manager::getInt("resolution x", "Video"); + int y = Settings::Manager::getInt("resolution y", "Video"); + mHud->onResChange(x, y); + mConsole->onResChange(x, y); + mMenu->onResChange(x, y); + mSettingsWindow->center(); + mAlchemyWindow->center(); + mScrollWindow->center(); + mBookWindow->center(); + mQuickKeysMenu->center(); + mSpellBuyingWindow->center(); + mLoadingScreen->onResChange (x,y); + mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); + mInputBlocker->setSize(MyGUI::IntSize(x,y)); + } + if (windowRecreated) + { + mGuiManager->updateWindow (mRendering->getWindow ()); + mLoadingScreen->updateWindow (mRendering->getWindow ()); + } + } + + void WindowManager::pushGuiMode(GuiMode mode) + { + if (mode==GM_Inventory && mAllowed==GW_None) + return; + + + // If this mode already exists somewhere in the stack, just bring it to the front. + if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end()) + { + mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode)); + } + + mGuiModes.push_back(mode); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::popGuiMode() + { + if (!mGuiModes.empty()) + mGuiModes.pop_back(); + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + 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; + } + + bool gameMode = !isGuiMode(); + MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode); + + updateVisible(); + } + + void WindowManager::setSelectedSpell(const std::string& spellId, int successChancePercent) + { + mHud->setSelectedSpell(spellId, successChancePercent); + + const ESM::Spell* spell = + MWBase::Environment::get().getWorld()->getStore().get().find(spellId); + + mSpellWindow->setTitle(spell->mName); + } + + void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item) + { + const ESM::Enchantment* ench = MWBase::Environment::get().getWorld()->getStore().get() + .find(MWWorld::Class::get(item).getEnchantment(item)); + + int chargePercent = item.getCellRef().mEnchantmentCharge / static_cast(ench->mData.mCharge) * 100; + mHud->setSelectedEnchantItem(item, chargePercent); + mSpellWindow->setTitle(MWWorld::Class::get(item).getName(item)); + } + + void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item) + { + int durabilityPercent = item.getCellRef().mCharge / static_cast(MWWorld::Class::get(item).getItemMaxHealth(item)) * 100; + mHud->setSelectedWeapon(item, durabilityPercent); + mInventoryWindow->setTitle(MWWorld::Class::get(item).getName(item)); + } + + void WindowManager::unsetSelectedSpell() + { + mHud->unsetSelectedSpell(); + mSpellWindow->setTitle("#{sNone}"); + } + + void WindowManager::unsetSelectedWeapon() + { + mHud->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 mHud->getWorldMouseOver(); + } + + void WindowManager::executeInConsole (const std::string& path) + { + mConsole->executeFile (path); + } + + void WindowManager::wmUpdateFps(float fps, unsigned int triangleCount, unsigned int batchCount) + { + mFPS = fps; + mTriangleCount = triangleCount; + mBatchCount = batchCount; + } + + MyGUI::Gui* WindowManager::getGui() const { return mGui; } + + MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } + MWGui::ContainerWindow* WindowManager::getContainerWindow() { return mContainerWindow; } + MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } + MWGui::BookWindow* WindowManager::getBookWindow() { return mBookWindow; } + MWGui::ScrollWindow* WindowManager::getScrollWindow() { return mScrollWindow; } + MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } + MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog() { return mConfirmationDialog; } + MWGui::TradeWindow* WindowManager::getTradeWindow() { return mTradeWindow; } + MWGui::SpellBuyingWindow* WindowManager::getSpellBuyingWindow() { return mSpellBuyingWindow; } + MWGui::TravelWindow* WindowManager::getTravelWindow() { return mTravelWindow; } + MWGui::SpellWindow* WindowManager::getSpellWindow() { return mSpellWindow; } + MWGui::Console* WindowManager::getConsole() { return mConsole; } + + bool WindowManager::isAllowed (GuiWindow wnd) const + { + return mAllowed & wnd; + } + + void WindowManager::allow (GuiWindow wnd) + { + mAllowed = (GuiWindow)(mAllowed | wnd); + + if (wnd & GW_Inventory) + { + mBookWindow->setInventoryAllowed (true); + mScrollWindow->setInventoryAllowed (true); + } + + updateVisible(); + } + + void WindowManager::disallowAll() + { + mAllowed = GW_None; + + mBookWindow->setInventoryAllowed (false); + mScrollWindow->setInventoryAllowed (false); + + updateVisible(); + } + + void WindowManager::toggleVisible (GuiWindow wnd) + { + mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); + updateVisible(); + } + + bool WindowManager::isGuiMode() const + { + return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); + } + + bool WindowManager::isConsoleMode() const + { + if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) + return true; + return false; + } + + MWGui::GuiMode WindowManager::getMode() const + { + if (mGuiModes.empty()) + return GM_None; + return mGuiModes.back(); + } + + std::map > WindowManager::getPlayerSkillValues() + { + return mPlayerSkillValues; + } + + std::map > WindowManager::getPlayerAttributeValues() + { + return mPlayerAttributes; + } + + WindowManager::SkillList WindowManager::getPlayerMinorSkills() + { + return mPlayerMinorSkills; + } + + WindowManager::SkillList WindowManager::getPlayerMajorSkills() + { + return mPlayerMajorSkills; + } + + void WindowManager::disallowMouse() + { + mInputBlocker->setVisible (true); + } + + void WindowManager::allowMouse() + { + mInputBlocker->setVisible (!isGuiMode ()); + } + + void WindowManager::notifyInputActionBound () + { + mSettingsWindow->updateControlsBox (); + allowMouse(); + } + + void WindowManager::showCrosshair (bool show) + { + mHud->setCrosshairVisible (show && mCrosshairEnabled); + } + + void WindowManager::activateQuickKey (int index) + { + mQuickKeysMenu->activateQuickKey(index); + } + + bool WindowManager::getSubtitlesEnabled () + { + return mSubtitlesEnabled; + } + + void WindowManager::toggleHud () + { + mHudEnabled = !mHudEnabled; + mHud->setVisible (mHudEnabled); + } + + void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) + { + mLoadingScreen->setLoadingProgress (stage, depth, current, total); + } + + void WindowManager::loadingDone () + { + mLoadingScreen->loadingDone (); + } + + bool WindowManager::getPlayerSleeping () + { + return mWaitDialog->getSleeping(); + } + + void WindowManager::wakeUpPlayer() + { + mWaitDialog->wakeUp(); + } + + void WindowManager::addVisitedLocation(const std::string& name, int x, int y) + { + mMap->addVisitedLocation (name, x, y); + } + + void WindowManager::startSpellMaking(MWWorld::Ptr actor) + { + mSpellCreationDialog->startSpellMaking (actor); + } + + void WindowManager::startEnchanting (MWWorld::Ptr actor) + { + mEnchantingDialog->startEnchanting (actor); + } + + void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) + { + mEnchantingDialog->startSelfEnchanting(soulgem); + } + + void WindowManager::startTraining(MWWorld::Ptr actor) + { + mTrainingWindow->startTraining(actor); + } + + void WindowManager::startRepair(MWWorld::Ptr actor) + { + mMerchantRepair->startRepair(actor); + } + + void WindowManager::startRepairItem(MWWorld::Ptr item) + { + mRepair->startRepairItem(item); + } + + const Translation::Storage& WindowManager::getTranslationDataStorage() const + { + return mTranslationDataStorage; + } + + void WindowManager::showCompanionWindow(MWWorld::Ptr actor) + { + mCompanionWindow->open(actor); + } + + void WindowManager::changePointer(const std::string &name) + { + mCursor->onCursorChange(name); + } + + void WindowManager::showSoulgemDialog(MWWorld::Ptr item) + { + mSoulgemDialog->show(item); + } + + void WindowManager::frameStarted (float dt) + { + mInventoryWindow->doRenderUpdate (); } - updateVisible(); -} - -void WindowManager::disallowAll() -{ - mAllowed = GW_None; - - mBookWindow->setInventoryAllowed (false); - mScrollWindow->setInventoryAllowed (false); - - updateVisible(); -} - -void WindowManager::toggleVisible (GuiWindow wnd) -{ - mShown = (mShown & wnd) ? (GuiWindow) (mShown & ~wnd) : (GuiWindow) (mShown | wnd); - updateVisible(); -} - -bool WindowManager::isGuiMode() const -{ - return !mGuiModes.empty() || mMessageBoxManager->isInteractiveMessageBox(); -} - -bool WindowManager::isConsoleMode() const -{ - if (!mGuiModes.empty() && mGuiModes.back()==GM_Console) - return true; - return false; -} - -MWGui::GuiMode WindowManager::getMode() const -{ - if (mGuiModes.empty()) - return GM_None; - return mGuiModes.back(); -} - -std::map > WindowManager::getPlayerSkillValues() -{ - return mPlayerSkillValues; -} - -std::map > WindowManager::getPlayerAttributeValues() -{ - return mPlayerAttributes; -} - -WindowManager::SkillList WindowManager::getPlayerMinorSkills() -{ - return mPlayerMinorSkills; -} - -WindowManager::SkillList WindowManager::getPlayerMajorSkills() -{ - return mPlayerMajorSkills; -} - -void WindowManager::disallowMouse() -{ - mInputBlocker->setVisible (true); -} - -void WindowManager::allowMouse() -{ - mInputBlocker->setVisible (!isGuiMode ()); -} - -void WindowManager::notifyInputActionBound () -{ - mSettingsWindow->updateControlsBox (); - allowMouse(); -} - -void WindowManager::showCrosshair (bool show) -{ - mHud->setCrosshairVisible (show && mCrosshairEnabled); -} - -void WindowManager::activateQuickKey (int index) -{ - mQuickKeysMenu->activateQuickKey(index); -} - -bool WindowManager::getSubtitlesEnabled () -{ - return mSubtitlesEnabled; -} - -void WindowManager::toggleHud () -{ - mHudEnabled = !mHudEnabled; - mHud->setVisible (mHudEnabled); -} - -void WindowManager::setLoadingProgress (const std::string& stage, int depth, int current, int total) -{ - mLoadingScreen->setLoadingProgress (stage, depth, current, total); -} - -void WindowManager::loadingDone () -{ - mLoadingScreen->loadingDone (); -} - -bool WindowManager::getPlayerSleeping () -{ - return mWaitDialog->getSleeping(); -} - -void WindowManager::wakeUpPlayer() -{ - mWaitDialog->wakeUp(); -} - -void WindowManager::addVisitedLocation(const std::string& name, int x, int y) -{ - mMap->addVisitedLocation (name, x, y); -} - -void WindowManager::startSpellMaking(MWWorld::Ptr actor) -{ - mSpellCreationDialog->startSpellMaking (actor); -} - -void WindowManager::startEnchanting (MWWorld::Ptr actor) -{ - mEnchantingDialog->startEnchanting (actor); -} - -void WindowManager::startSelfEnchanting(MWWorld::Ptr soulgem) -{ - mEnchantingDialog->startSelfEnchanting(soulgem); -} - -void WindowManager::startTraining(MWWorld::Ptr actor) -{ - mTrainingWindow->startTraining(actor); -} - -void WindowManager::startRepair(MWWorld::Ptr actor) -{ - mMerchantRepair->startRepair(actor); -} - -void WindowManager::startRepairItem(MWWorld::Ptr item) -{ - mRepair->startRepairItem(item); -} - -const Translation::Storage& WindowManager::getTranslationDataStorage() const -{ - return mTranslationDataStorage; -} - -void WindowManager::showCompanionWindow(MWWorld::Ptr actor) -{ - mCompanionWindow->open(actor); -} - -void WindowManager::changePointer(const std::string &name) -{ - mCursor->onCursorChange(name); -} - -void WindowManager::showSoulgemDialog(MWWorld::Ptr item) -{ - mSoulgemDialog->show(item); -} - -void WindowManager::frameStarted (float dt) -{ - mInventoryWindow->doRenderUpdate (); } diff --git a/apps/openmw/mwgui/windowpinnablebase.cpp b/apps/openmw/mwgui/windowpinnablebase.cpp index 53ba1b9fd6..e5a94fc721 100644 --- a/apps/openmw/mwgui/windowpinnablebase.cpp +++ b/apps/openmw/mwgui/windowpinnablebase.cpp @@ -2,25 +2,26 @@ #include "exposedwindow.hpp" -using namespace MWGui; - -WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) - : WindowBase(parLayout), mPinned(false), mVisible(false) +namespace MWGui { - ExposedWindow* window = static_cast(mMainWidget); - mPinButton = window->getSkinWidget ("Button"); + WindowPinnableBase::WindowPinnableBase(const std::string& parLayout) + : WindowBase(parLayout), mPinned(false), mVisible(false) + { + ExposedWindow* window = static_cast(mMainWidget); + mPinButton = window->getSkinWidget ("Button"); - mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); -} - -void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) -{ - mPinned = !mPinned; - - if (mPinned) - mPinButton->changeWidgetSkin ("PinDown"); - else - mPinButton->changeWidgetSkin ("PinUp"); - - onPinToggled(); + mPinButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WindowPinnableBase::onPinButtonClicked); + } + + void WindowPinnableBase::onPinButtonClicked(MyGUI::Widget* _sender) + { + mPinned = !mPinned; + + if (mPinned) + mPinButton->changeWidgetSkin ("PinDown"); + else + mPinButton->changeWidgetSkin ("PinUp"); + + onPinToggled(); + } } From 3c5e4ceefd87140156bfa87c314242baef30676e Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 16:46:32 +0200 Subject: [PATCH 0449/1537] Workaround for ambiguous "Chargen_plank" ID in chargen script (one at -22,16 and one at -2,-9) --- apps/openmw/mwworld/store.hpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index f69f606b45..fb3f8c4826 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -415,8 +415,18 @@ namespace MWWorld } }; - typedef std::map DynamicInt; - typedef std::map, ESM::Cell> DynamicExt; + struct DynamicExtCmp + { + bool operator()(const std::pair &left, const std::pair &right) const { + if (left.first == right.first) { + return left.second < right.second; + } + return left.first < right.first; + } + }; + + typedef std::map DynamicInt; + typedef std::map, ESM::Cell, DynamicExtCmp> DynamicExt; DynamicInt mInt; DynamicExt mExt; From b34caccd2ec90a582e4732d29fb1fc7a10a86e92 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 16:46:38 +0200 Subject: [PATCH 0450/1537] Fix moving NPCs not getting their collision box moved --- libs/openengine/bullet/physic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index 524f57c1c4..eaeae7dc39 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -511,8 +511,8 @@ namespace Physic void PhysicEngine::stepSimulation(double deltaT) { - // This isn't needed as there are no dynamic objects at this point - //dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); + // This seems to be needed for character controller objects + dynamicsWorld->stepSimulation(deltaT,10, 1/60.0); if(isDebugCreated) { mDebugDrawer->step(); From c753eb4c287729759e897ef35fdd6b36b3acf429 Mon Sep 17 00:00:00 2001 From: gus Date: Thu, 18 Apr 2013 18:35:01 +0100 Subject: [PATCH 0451/1537] another way to do pathfinding. Slightly less powerfull algorithme in theory, but morrowind pathgrids are so simple it shouldn't be a problem. Hope it solves the bug for KittyCat --- apps/openmw/mwmechanics/pathfinding.cpp | 35 ++++++++++++++++++------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index 7c22e54701..2f27d25f8a 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -1,5 +1,5 @@ #include "pathfinding.hpp" -#include +#include #include #include "boost/tuple/tuple.hpp" #include "OgreMath.h" @@ -55,7 +55,7 @@ namespace struct found_path {}; - class goalVisited : public boost::default_astar_visitor + /*class goalVisited : public boost::default_astar_visitor { public: goalVisited(PointID goal) : mGoal(goal) {} @@ -69,7 +69,7 @@ namespace PointID mGoal; }; - class DistanceHeuristic : public boost::astar_heuristic + class DistanceHeuristic : public boost::atasr_heuristic { public: DistanceHeuristic(const PathGridGraph & l, PointID goal) @@ -87,11 +87,23 @@ namespace private: const PathGridGraph & mGraph; PointID mGoal; - }; -} + };*/ + + class goalVisited : public boost::default_dijkstra_visitor + { + public: + goalVisited(PointID goal) : mGoal(goal) {} + + void examine_vertex(PointID u, const PathGridGraph g) + { + if(u == mGoal) + throw found_path(); + } + private: + PointID mGoal; + }; + -namespace MWMechanics -{ PathGridGraph buildGraph(const ESM::Pathgrid* pathgrid,float xCell = 0,float yCell = 0) { PathGridGraph graph; @@ -126,13 +138,12 @@ namespace MWMechanics std::list shortest_path; try { - boost::astar_search + boost::dijkstra_shortest_paths ( graph, start, - DistanceHeuristic(graph,end), boost::predecessor_map(&p[0]).distance_map(&d[0]).visitor(goalVisited(end))//.weight_map(boost::get(&Edge::distance, graph)) - ); + ); } catch(found_path fg) { for(PointID v = end;; v = p[v]) { @@ -146,6 +157,10 @@ namespace MWMechanics //end of helpers functions +} + +namespace MWMechanics +{ PathFinder::PathFinder() { mIsPathConstructed = false; From f9deb593d1f5d6baba89b57cc8f5f3ba544917a6 Mon Sep 17 00:00:00 2001 From: Glorf Date: Thu, 18 Apr 2013 21:37:58 +0200 Subject: [PATCH 0452/1537] Bugfix #578 --- apps/openmw/mwmechanics/mechanicsmanagerimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index d34c4b97f5..66d20e662c 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -548,7 +548,7 @@ namespace MWMechanics float bribeMod; if (type == PT_Bribe10) bribeMod = gmst.find("fBribe10Mod")->getFloat(); - if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); + else if (type == PT_Bribe100) bribeMod = gmst.find("fBribe100Mod")->getFloat(); else bribeMod = gmst.find("fBribe1000Mod")->getFloat(); float target3 = d * (playerRating3 - npcRating3 + 50) + bribeMod; From 3b3a052f4f7592b756583a0bc7fdadfe04b5a920 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Apr 2013 22:36:48 +0200 Subject: [PATCH 0453/1537] 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 b6a1017906..9f12b11fda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 22) +set (OPENMW_VERSION_MINOR 23) 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 8edb0c4b31..9bce063fa2 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.22.0 +Version: 0.23.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org From 257f9403660e82f3fed9231c6784429b13fdea38 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 18 Apr 2013 22:50:04 +0200 Subject: [PATCH 0454/1537] updated changelog --- readme.txt | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/readme.txt b/readme.txt index 9bce063fa2..5f38457765 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,65 @@ Allowed options: CHANGELOG +0.23.0 + +Bug #522: Player collides with placeable items +Bug #553: Open/Close sounds played when accessing main menu w/ Journal Open +Bug #561: Tooltip word wrapping delay +Bug #578: Bribing works incorrectly +Bug #601: PositionCell fails on negative coordinates +Bug #606: Some NPCs hairs not rendered with Better Heads addon +Bug #609: Bad rendering of bone boots +Bug #613: Messagebox causing assert to fail +Bug #631: Segfault on shutdown +Bug #634: Exception when talking to Calvus Horatius in Mournhold, royal palace courtyard +Bug #635: Scale NPCs depending on race +Bug #643: Dialogue Race select function is inverted +Bug #646: Twohanded weapons don't work properly +Bug #654: Crash when dropping objects without a collision shape +Bug #655/656: Objects that were disabled or deleted (but not both) were added to the scene when re-entering a cell +Bug #660: "g" in "change" cut off in Race Menu +Bug #661: Arrille sells me the key to his upstairs room +Bug #662: Day counter starts at 2 instead of 1 +Bug #663: Cannot select "come unprepared" topic in dialog with Dagoth Ur +Bug #665: Pickpocket -> "Grab all" grabs all NPC inventory, even not listed in container window. +Bug #666: Looking up/down problem +Bug #667: Active effects border visible during loading +Bug #669: incorrect player position at new game start +Bug #670: race selection menu: sex, face and hair left button not totally clickable +Bug #671: new game: player is naked +Bug #674: buying or selling items doesn't change amount of gold +Bug #675: fatigue is not set to its maximum when starting a new game +Bug #678: Wrong rotation order causes RefData's rotation to be stored incorrectly +Bug #680: different gold coins in Tel Mara +Bug #682: Race menu ignores playable flag for some hairs and faces +Bug #685: Script compiler does not accept ":" after a function name +Bug #688: dispose corpse makes cross-hair to disappear +Bug #691: Auto equipping ignores equipment conditions +Bug #692: OpenMW doesnt load "loose file" texture packs that places resources directly in data folder +Bug #696: Draugr incorrect head offset +Bug #697: Sail transparency issue +Bug #700: "On the rocks" mod does not load its UV coordinates correctly. +Bug #702: Some race mods don't work +Bug #711: Crash during character creation +Bug #715: Growing Tauryon +Feature #55/657: Item Repairing +Feature #62/87: Enchanting +Feature #99: Pathfinding +Feature #104: AI Package: Travel +Feature #129: Levelled items +Feature #204: Texture animations +Feature #239: Fallback-Settings +Feature #535: Console object selection improvements +Feature #629: Add levelup description in levelup layout dialog +Feature #630: Optional format subrecord in (tes3) header +Feature #641: Armor rating +Feature #645: OnDeath script function +Feature #683: Companion item UI +Feature #698: Basic Particles +Task #648: Split up components/esm/loadlocks +Task #695: mwgui cleanup + 0.22.0 Bug #311: Potential infinite recursion in script compiler From ef9afeb53e5b48fd3a903a1e26a8a869ef89e7ee Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 0455/1537] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb15..ea49ae4a4c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 92e06cebf3f6cbd0930529ab026221c5ff2c69ca Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 0456/1537] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f38457765..d5a5dcc183 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From e92897526c9fb6bc8fb1acf836b7b841374cc919 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 0457/1537] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586fe..a0a4ab0aea 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8b..9535f2a24e 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 50bb92beb349f340801923565db15c1c78832c38 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 02:01:50 -0700 Subject: [PATCH 0458/1537] Use a method to set the visibility flags and render queue. --- apps/openmw/mwrender/activatoranimation.cpp | 24 +------------------ apps/openmw/mwrender/animation.cpp | 26 +++++++++++++++++++++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/creatureanimation.cpp | 25 +------------------- apps/openmw/mwrender/npcanimation.cpp | 21 ++++------------- 5 files changed, 35 insertions(+), 63 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index 1f9a2e23c9..c3a3045c20 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -1,10 +1,5 @@ #include "activatoranimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -27,24 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Misc); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Misc); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 11876a2473..8e5bd01081 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include #include #include @@ -150,6 +152,30 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mCurrentControllers = &objlist.mControllers; } +void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) +{ + for(size_t i = 0;i < objlist.mEntities.size();i++) + { + Ogre::Entity *ent = objlist.mEntities[i]; + if(visflags != 0) + ent->setVisibilityFlags(visflags); + + for(unsigned int j = 0;j < ent->getNumSubEntities();++j) + { + Ogre::SubEntity* subEnt = ent->getSubEntity(j); + subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? transqueue : solidqueue); + } + } + for(size_t i = 0;i < objlist.mParticles.size();i++) + { + Ogre::ParticleSystem *part = objlist.mParticles[i]; + if(visflags != 0) + part->setVisibilityFlags(visflags); + // TODO: Check particle material for actual transparency + part->setRenderQueueGroup(transqueue); + } +} + Ogre::Node *Animation::getNode(const std::string &name) { diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f8ddceeaa3..db2195c342 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -85,6 +85,8 @@ protected: void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); + static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index a48b8da9f8..51632b2ee1 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -1,10 +1,5 @@ #include "creatureanimation.hpp" -#include -#include -#include -#include - #include "renderconst.hpp" #include "../mwbase/world.hpp" @@ -30,25 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - - const NifOgre::ObjectList &objlist = mObjectLists.back(); - for(size_t i = 0;i < objlist.mEntities.size();i++) - { - Ogre::Entity *ent = objlist.mEntities[i]; - ent->setVisibilityFlags(RV_Actors); - - for(unsigned int j=0; j < ent->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = ent->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } - for(size_t i = 0;i < objlist.mParticles.size();i++) - { - Ogre::ParticleSystem *part = objlist.mParticles[i]; - part->setVisibilityFlags(RV_Actors); - part->setRenderQueueGroup(RQG_Alpha); - } + setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index cea0225ef9..0b05b4ba66 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -361,25 +361,13 @@ void NpcAnimation::updateParts(bool forceupdate) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) { NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model); - for(size_t i = 0;i < objects.mEntities.size();i++) - { - objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mEntities[i]->setVisibilityFlags(mVisibilityFlags); + setRenderProperties(objects, mVisibilityFlags, RQG_Main, RQG_Alpha); - for(unsigned int j=0; j < objects.mEntities[i]->getNumSubEntities(); ++j) - { - Ogre::SubEntity* subEnt = objects.mEntities[i]->getSubEntity(j); - subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); - } - } + for(size_t i = 0;i < objects.mEntities.size();i++) + objects.mEntities[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); for(size_t i = 0;i < objects.mParticles.size();i++) - { objects.mParticles[i]->getUserObjectBindings().setUserAny(Ogre::Any(group)); - if(mVisibilityFlags != 0) - objects.mParticles[i]->setVisibilityFlags(mVisibilityFlags); - objects.mParticles[i]->setRenderQueueGroup(RQG_Alpha); - } + if(objects.mSkelBase) { Ogre::AnimationStateSet *aset = objects.mSkelBase->getAllAnimationStates(); @@ -395,6 +383,7 @@ NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, in while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); } + return objects; } From f13b0c884fa1eb4a93060a1722f45677bf458d08 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 0459/1537] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea8..41770d4891 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From a8e3acd6c4db2c502e3f1de49bb054d53ba4ca5f Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 0460/1537] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76cd..220adf566a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 1051fa51a71f964fa55a73d054c558862ee95ed0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 15:07:08 -0700 Subject: [PATCH 0461/1537] Recognize NiFlipController --- components/nif/controller.hpp | 23 +++++++++++++++++++++++ components/nif/niffile.cpp | 1 + components/nif/record.hpp | 1 + components/nif/recordptr.hpp | 1 + 4 files changed, 26 insertions(+) diff --git a/components/nif/controller.hpp b/components/nif/controller.hpp index aa6a9ef4ff..011e0e4452 100644 --- a/components/nif/controller.hpp +++ b/components/nif/controller.hpp @@ -303,5 +303,28 @@ public: } }; +class NiFlipController : public Controller +{ +public: + int mTexSlot; + float mDelta; // Time between two flips. delta = (start_time - stop_time) / num_sources + NiSourceTextureList mSources; + + void read(NIFStream *nif) + { + Controller::read(nif); + mTexSlot = nif->getUInt(); + /*unknown=*/nif->getUInt();/*0?*/ + mDelta = nif->getFloat(); + mSources.read(nif); + } + + void post(NIFFile *nif) + { + Controller::post(nif); + mSources.post(nif); + } +}; + } // Namespace #endif diff --git a/components/nif/niffile.cpp b/components/nif/niffile.cpp index 2c4f3506ea..a66bd99db5 100644 --- a/components/nif/niffile.cpp +++ b/components/nif/niffile.cpp @@ -235,6 +235,7 @@ static const RecordFactoryEntry recordFactories [] = { { "NiMaterialColorController", &construct , RC_NiMaterialColorController }, { "NiBSPArrayController", &construct , RC_NiBSPArrayController }, { "NiParticleSystemController", &construct , RC_NiParticleSystemController }, + { "NiFlipController", &construct , RC_NiFlipController }, { "NiAmbientLight", &construct , RC_NiLight }, { "NiDirectionalLight", &construct , RC_NiLight }, { "NiTextureEffect", &construct , RC_NiTextureEffect }, diff --git a/components/nif/record.hpp b/components/nif/record.hpp index 97b10503e8..3f852ed837 100644 --- a/components/nif/record.hpp +++ b/components/nif/record.hpp @@ -60,6 +60,7 @@ enum RecordType RC_NiMaterialColorController, RC_NiBSPArrayController, RC_NiParticleSystemController, + RC_NiFlipController, RC_NiBSAnimationNode, RC_NiLight, RC_NiTextureEffect, diff --git a/components/nif/recordptr.hpp b/components/nif/recordptr.hpp index c5bafea124..2ecde7f60e 100644 --- a/components/nif/recordptr.hpp +++ b/components/nif/recordptr.hpp @@ -163,6 +163,7 @@ typedef RecordPtrT NiAutoNormalParticlesDataPtr; typedef RecordListT NodeList; typedef RecordListT PropertyList; +typedef RecordListT NiSourceTextureList; } // Namespace #endif From f37a71f02584dddfe50655dea4689aaea4bf89f3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 19 Apr 2013 23:56:47 -0700 Subject: [PATCH 0462/1537] Use a separate method to build node-based controllers --- components/nifogre/ogrenifloader.cpp | 77 +++++++++++++++------------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index c5cc45ae9f..21acfca0fb 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -575,6 +575,44 @@ class NIFObjectLoader } + static void createNodeControllers(const std::string &name, Nif::ControllerPtr ctrl, ObjectList &objectlist, int animflags) + { + do { + if(ctrl->recType == Nif::RC_NiVisController) + { + const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + else if(ctrl->recType == Nif::RC_NiKeyframeController) + { + const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); + if(!key->data.empty()) + { + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); + Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } + } + ctrl = ctrl->next; + } while(!ctrl.empty()); + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -613,6 +651,9 @@ class NIFObjectLoader e = e->extra; } + if(!node->controller.empty()) + createNodeControllers(name, node->controller, objectlist, animflags); + if(node->recType == Nif::RC_NiCamera) { int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); @@ -620,42 +661,6 @@ class NIFObjectLoader objectlist.mCameras.push_back(trgtbone); } - Nif::ControllerPtr ctrl = node->controller; - while(!ctrl.empty()) - { - if(ctrl->recType == Nif::RC_NiVisController) - { - const Nif::NiVisController *vis = static_cast(ctrl.getPtr()); - - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW VisController::Value(trgtbone, vis->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW VisController::Function(vis, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - else if(ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, ctrl->target->recIndex); - Ogre::Bone *trgtbone = objectlist.mSkelBase->getSkeleton()->getBone(trgtid); - Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? - Ogre::ControllerManager::getSingleton().getFrameTimeSource() : - Ogre::ControllerValueRealPtr()); - Ogre::ControllerValueRealPtr dstval(OGRE_NEW KeyframeController::Value(trgtbone, key->data.getPtr())); - Ogre::ControllerFunctionRealPtr func(OGRE_NEW KeyframeController::Function(key, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); - - objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); - } - } - ctrl = ctrl->next; - } - if(node->recType == Nif::RC_NiTriShape && !(flags&0x80000000)) { createEntity(name, group, sceneMgr, objectlist, node, flags, animflags); From ace7d647e5af1182a972505bb6f3aa1a01ee16d3 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 15:35:19 -0700 Subject: [PATCH 0463/1537] Add a method to apply a NodeTargetValue-based controller to a specified node. --- components/nifogre/ogrenifloader.cpp | 147 +++++++++++++++------------ components/nifogre/ogrenifloader.hpp | 2 + 2 files changed, 82 insertions(+), 67 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 21acfca0fb..90147a43bc 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -104,7 +104,7 @@ public: private: std::vector mData; - virtual bool calculate(Ogre::Real time) + bool calculate(Ogre::Real time) const { if(mData.size() == 0) return true; @@ -144,16 +144,21 @@ public: , mData(data->mVis) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + bool vis = calculate(time); + setVisible(node, vis); + } + virtual Ogre::Real getValue() const { // Should not be called - return 1.0f; + return 0.0f; } virtual void setValue(Ogre::Real time) { - bool vis = calculate(time); - setVisible(mNode, vis); + Value::applyToNode(mNode, time); } }; @@ -170,6 +175,66 @@ public: Nif::Vector3KeyList mTranslations; Nif::FloatKeyList mScales; + static float interpKey(const Nif::FloatKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::FloatKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Vector3 interpKey(const Nif::Vector3KeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::Vector3KeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return last->mValue + ((iter->mValue - last->mValue)*a); + } + return keys.back().mValue; + } + + static Ogre::Quaternion interpKey(const Nif::QuaternionKeyList::VecType &keys, float time) + { + if(time <= keys.front().mTime) + return keys.front().mValue; + if(time >= keys.back().mTime) + return keys.back().mValue; + + Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); + for(;iter != keys.end();iter++) + { + if(iter->mTime < time) + continue; + + Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); + float a = (time-last->mTime) / (iter->mTime-last->mTime); + return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); + } + return Ogre::Quaternion(); + } + public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) : NodeTargetValue(target) @@ -178,6 +243,16 @@ public: , mScales(data->mScales) { } + virtual void applyToNode(Ogre::Node *node, float time) const + { + if(mRotations.mKeys.size() > 0) + node->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + node->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + } + virtual Ogre::Real getValue() const { // Should not be called @@ -186,69 +261,7 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) - { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } - } + Value::applyToNode(mNode, time); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index e3bb550640..b53815fa0f 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -85,6 +85,8 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } + virtual void applyToNode(Ogre::Node *node, float time) const = 0; + void setNode(Ogre::Node *target) { mNode = target; } Ogre::Node *getNode() const From 835ff8eb1eb36bc16cffaca85343ee86d1533275 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 20 Apr 2013 17:13:27 -0700 Subject: [PATCH 0464/1537] Avoid creating an AnimationValue per ObjectList --- apps/openmw/mwrender/animation.cpp | 6 +++--- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8e5bd01081..56b601727a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -32,7 +32,8 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mPtr(ptr) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + , mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -70,7 +71,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b mInsert = node->createChildSceneNode(); assert(mInsert); } - Ogre::SharedPtr > ctrlval(OGRE_NEW AnimationValue(this)); mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : NifOgre::Loader::createObjectBase(mInsert, model)); @@ -145,7 +145,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(ctrlval); + objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } if(!mCurrentControllers || (*mCurrentControllers).size() == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index db2195c342..d3cb6bebb7 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,6 +38,7 @@ protected: mAnimation->mCurrentTime = value; } }; + Ogre::SharedPtr > mAnimationBaseValuePtr; MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; From 19325f9d40944df8c6b312d309469e59e3c6c520 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 0465/1537] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c4826..2bd61c2b02 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From 8bf1149cec0da1e8f7c59089c01b8804c9897cf9 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 0466/1537] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d929..86a85be18e 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui 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) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From d7c9df16f81ceebc7ee5da0b5242d33814a7e85e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:32:34 -0700 Subject: [PATCH 0467/1537] Store the current animation group --- apps/openmw/mwrender/animation.cpp | 3 ++- apps/openmw/mwrender/animation.hpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 56b601727a..ea27cbb5e1 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -441,9 +441,10 @@ void Animation::play(const std::string &groupname, const std::string &start, con Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); mCurrentKeys = &mTextKeys[groupname]; + mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; + mAnimVelocity = 0.0f; if(mNonAccumRoot) calcAnimVelocity(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index d3cb6bebb7..472a6289c9 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -53,6 +53,7 @@ protected: Ogre::Vector3 mLastPosition; Ogre::Animation *mCurrentAnim; + std::string mCurrentGroup; std::vector > *mCurrentControllers; NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; From 6c85d6763aec95b2f3367fea90437f4e818042e5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 18:38:25 -0700 Subject: [PATCH 0468/1537] Pass "loop stop" to the character controller --- apps/openmw/mwmechanics/character.cpp | 9 +++++++++ apps/openmw/mwrender/animation.cpp | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 02a5aa1006..16d8115284 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,6 +150,15 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { + if(evt == "loop stop") + { + if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) + { + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "loop start", "stop", false); + } + return; + } if(evt == "stop") { if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index ea27cbb5e1..68fae99ddf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -409,10 +409,10 @@ bool Animation::handleEvent(float time, const std::string &evt) reset("loop start"); if(mCurrentTime >= time) return false; + return true; } - return true; } - if(evt == "stop") + else if(evt == "stop") { if(mLooping) { From 7d59340ed6c27b4b895e9e9b7200c35bc612714c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:13:49 -0700 Subject: [PATCH 0469/1537] Don't clip out the group name from the textkeys --- apps/openmw/mwrender/animation.cpp | 39 +++++++++++++++++++----------- components/nifogre/skeleton.cpp | 12 +-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 68fae99ddf..2f2ffccb5e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -243,14 +243,16 @@ void Animation::calcAnimVelocity() if(track && track->getNumKeyFrames() > 1) { + const std::string loopstart = mCurrentGroup+": loop start"; + const std::string loopstop = mCurrentGroup+": loop stop"; float loopstarttime = 0.0f; float loopstoptime = mCurrentAnim->getLength(); NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); while(keyiter != mCurrentKeys->end()) { - if(keyiter->second == "loop start") + if(keyiter->second == loopstart) loopstarttime = keyiter->first; - else if(keyiter->second == "loop stop") + else if(keyiter->second == loopstop) { loopstoptime = keyiter->first; break; @@ -383,12 +385,6 @@ void Animation::reset(const std::string &start, const std::string &stop) bool Animation::handleEvent(float time, const std::string &evt) { - if(evt == "start" || evt == "loop start") - { - /* Do nothing */ - return true; - } - if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -402,21 +398,36 @@ bool Animation::handleEvent(float time, const std::string &evt) return true; } - if(evt == "loop stop") + if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || + evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + { + // Not ours + return true; + } + size_t off = mCurrentGroup.size()+2; + size_t len = evt.size() - off; + + if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) + { + /* Do nothing */ + return true; + } + + if(evt.compare(off, len, "loop stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; } } - else if(evt == "stop") + else if(evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset("loop start"); + reset(mCurrentGroup+": loop start"); if(mCurrentTime >= time) return false; return true; @@ -424,7 +435,7 @@ bool Animation::handleEvent(float time, const std::string &evt) // fall-through } if(mController) - mController->markerEvent(time, evt); + mController->markerEvent(time, evt.substr(off)); return true; } @@ -455,7 +466,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!found) throw std::runtime_error("Failed to find animation "+groupname); - reset(start, stop); + reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); setLooping(loop); mPlaying = true; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 75bc907152..5eb0436143 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -282,17 +282,7 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - TextKeyMap::const_iterator insiter(keyiter); - TextKeyMap groupkeys; - do { - sep = insiter->second.find(':'); - if(sep == currentgroup.length() && insiter->second.compare(0, sep, currentgroup) == 0) - groupkeys.insert(std::make_pair(insiter->first, insiter->second.substr(sep+2))); - else if((sep == sizeof("soundgen")-1 && insiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && insiter->second.compare(0, sep, "sound") == 0)) - groupkeys.insert(std::make_pair(insiter->first, insiter->second)); - } while(insiter++ != lastkeyiter); - + TextKeyMap groupkeys(keyiter, ++lastkeyiter); bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 2345b5e8b3d7ebe69ef901098ac9d4603973ad09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 21 Apr 2013 22:56:40 -0700 Subject: [PATCH 0470/1537] Avoid storing text keys for each animation --- apps/openmw/mwrender/animation.cpp | 15 +++------------ apps/openmw/mwrender/animation.hpp | 1 - components/nifogre/ogrenifloader.hpp | 2 ++ components/nifogre/skeleton.cpp | 7 +------ 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2f2ffccb5e..d51a30a770 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -121,24 +121,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b Ogre::Bone *bone = boneiter.getNext(); Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty() || !Ogre::any_cast(data)) - continue; + if(data.isEmpty()) continue; + objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); } - for(int i = 0;i < skel->getNumAnimations();i++) - { - Ogre::Animation *anim = skel->getAnimation(i); - const Ogre::Any &groupdata = bindings.getUserAny(std::string(NifOgre::sTextKeyExtraDataID)+ - "@"+anim->getName()); - if(!groupdata.isEmpty()) - mTextKeys[anim->getName()] = Ogre::any_cast(groupdata); - } - break; } } @@ -451,7 +442,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &mTextKeys[groupname]; + mCurrentKeys = &iter->mTextKeys.begin()->second; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 472a6289c9..b60bd21a85 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -46,7 +46,6 @@ protected: Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjectLists; - std::map mTextKeys; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index b53815fa0f..8e220ea38d 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -50,6 +50,8 @@ struct ObjectList { // bones in the mSkelBase which are NiCamera nodes. std::vector mCameras; + std::map mTextKeys; + std::vector > mControllers; ObjectList() : mSkelBase(0) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 5eb0436143..3660be81bd 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,6 +193,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; + bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -255,9 +256,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) return; } - Ogre::UserObjectBindings &bindings = animroot->getUserObjectBindings(); - bindings.setUserAny(sTextKeyExtraDataID, Ogre::Any(true)); - std::string currentgroup; TextKeyMap::const_iterator keyiter = textkeys.begin(); for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) @@ -281,9 +279,6 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) } buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - - TextKeyMap groupkeys(keyiter, ++lastkeyiter); - bindings.setUserAny(std::string(sTextKeyExtraDataID)+"@"+currentgroup, Ogre::Any(groupkeys)); } } From 56b871e362724008c8bd4c5a686f63ce730f2a36 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 0471/1537] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0b..52c7bd4f34 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From a3511c62cf2c120636b4960f34f0a4973292d1c1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:01:30 -0700 Subject: [PATCH 0472/1537] Don't store textkeys in user object bindings It's a bit unwieldy to have them stored in the 'skeleton master' instead of the skeleton instance. And although the text keys are extracted for each created instance now, this shouldn't be much worse than the multimap copying going on before. Plus, proper serialization can help for future optimizations. --- apps/openmw/mwrender/animation.cpp | 16 +++------------- components/nifogre/ogrenifloader.cpp | 10 +++++++++- components/nifogre/skeleton.cpp | 11 +++++------ components/nifogre/skeleton.hpp | 3 +-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d51a30a770..31f54107eb 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -97,9 +97,9 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b while(boneiter.hasMoreElements()) boneiter.getNext()->setManuallyControlled(true); + Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); if(mSkelBase != objlist.mSkelBase) { - Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; @@ -114,23 +114,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b } } - Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(skelinst->getName()); - boneiter = skel->getBoneIterator(); - while(boneiter.hasMoreElements()) + if(objlist.mTextKeys.size() > 0) { - Ogre::Bone *bone = boneiter.getNext(); - Ogre::UserObjectBindings &bindings = bone->getUserObjectBindings(); - const Ogre::Any &data = bindings.getUserAny(NifOgre::sTextKeyExtraDataID); - if(data.isEmpty()) continue; - - objlist.mTextKeys[bone->getHandle()] = Ogre::any_cast(data); if(!mNonAccumRoot) { mAccumRoot = mInsert; - mNonAccumRoot = mSkelBase->getSkeleton()->getBone(bone->getName()); + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); } - - break; } } for(size_t i = 0;i < objlist.mControllers.size();i++) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 90147a43bc..97dfc59ef7 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -649,7 +649,14 @@ class NIFObjectLoader Nif::ExtraPtr e = node->extra; while(!e.empty()) { - if(e->recType == Nif::RC_NiStringExtraData) + if(e->recType == Nif::RC_NiTextKeyExtraData) + { + const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); + + int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); + objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + } + else if(e->recType == Nif::RC_NiStringExtraData) { const Nif::NiStringExtraData *sd = static_cast(e.getPtr()); // String markers may contain important information @@ -661,6 +668,7 @@ class NIFObjectLoader flags |= 0x80000000; } } + e = e->extra; } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 3660be81bd..1809212a78 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -193,7 +193,6 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); textkeys = extractTextKeys(tk); animroot = bone; - bone->getUserObjectBindings().setUserAny(sTextKeyExtraDataID, Ogre::Any(textkeys)); } e = e->extra; } @@ -287,16 +286,16 @@ Ogre::SkeletonPtr NIFSkeletonLoader::createSkeleton(const std::string &name, con { /* We need to be a little aggressive here, since some NIFs have a crap-ton * of nodes and Ogre only supports 256 bones. We will skip a skeleton if: - * There are no bones used for skinning, there are no controllers on non- - * NiTriShape nodes, there are no nodes named "AttachLight", and the tree - * consists of NiNode, NiTriShape, and RootCollisionNode types only. + * There are no bones used for skinning, there are no controllers, there + * are no nodes named "AttachLight", and the tree consists of NiNode, + * NiTriShape, and RootCollisionNode types only. */ if(!node->boneTrafo) { - if(node->recType == Nif::RC_NiTriShape) - return Ogre::SkeletonPtr(); if(node->controller.empty() && node->name != "AttachLight") { + if(node->recType == Nif::RC_NiTriShape) + return Ogre::SkeletonPtr(); if(node->recType == Nif::RC_NiNode || node->recType == Nif::RC_RootCollisionNode) { const Nif::NiNode *ninode = static_cast(node); diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index c69c2a12fe..e71dcfb158 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -37,8 +37,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader } static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index @@ -48,6 +46,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From a7776e124cda07bc69bae504eebe6ccdb14bb07f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 00:22:31 -0700 Subject: [PATCH 0473/1537] Only set mNonAccumRoot from mSkelBase --- apps/openmw/mwrender/animation.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 31f54107eb..54416c45a8 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -98,7 +98,15 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b boneiter.getNext()->setManuallyControlled(true); Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); - if(mSkelBase != objlist.mSkelBase) + if(mSkelBase == objlist.mSkelBase) + { + if(objlist.mTextKeys.size() > 0) + { + mAccumRoot = mInsert; + mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); + } + } + else { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -113,15 +121,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b dstval->setNode(bone); } } - - if(objlist.mTextKeys.size() > 0) - { - if(!mNonAccumRoot) - { - mAccumRoot = mInsert; - mNonAccumRoot = baseinst->getBone(objlist.mTextKeys.begin()->first); - } - } } for(size_t i = 0;i < objlist.mControllers.size();i++) { From a608e7ed06883ebc2b0ae09702bc133ffc2b1095 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 0474/1537] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc183..c033f95475 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 9485a4aa6df48e9370b87a9bee5aec812cdca003 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 01:40:41 -0700 Subject: [PATCH 0475/1537] Look through the whole animation stack to find the "velocity" --- apps/openmw/mwrender/animation.cpp | 55 +++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +-- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 54416c45a8..d71b33cddf 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,26 +209,26 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -void Animation::calcAnimVelocity() +float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) { const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); + Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); while(!track && trackiter.hasMoreElements()) { const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) + if(cur->getAssociatedNode()->getName() == bonename) track = cur; } if(track && track->getNumKeyFrames() > 1) { - const std::string loopstart = mCurrentGroup+": loop start"; - const std::string loopstop = mCurrentGroup+": loop stop"; + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = mCurrentAnim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = mCurrentKeys->begin(); - while(keyiter != mCurrentKeys->end()) + float loopstoptime = anim->getLength(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -245,13 +245,15 @@ void Animation::calcAnimVelocity() Ogre::TransformKeyFrame startkf(0, loopstarttime); Ogre::TransformKeyFrame endkf(0, loopstoptime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(loopstoptime), &endkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); + track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - mAnimVelocity = startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); + return startkf.getTranslate().distance(endkf.getTranslate()) / + (loopstoptime-loopstarttime); } } + + return 0.0f; } static void updateBoneTree(const Ogre::SkeletonInstance *skelsrc, Ogre::Bone *bone) @@ -423,27 +425,34 @@ bool Animation::handleEvent(float time, const std::string &evt) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { try { - bool found = false; + bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - mCurrentAnim = skel->getAnimation(groupname); - mCurrentKeys = &iter->mTextKeys.begin()->second; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; + Ogre::Animation *anim = skel->getAnimation(groupname); + const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + if(!foundanim) + { + mCurrentAnim = anim; + mCurrentKeys = keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; - mAnimVelocity = 0.0f; - if(mNonAccumRoot) - calcAnimVelocity(); + mAnimVelocity = 0.0f; + foundanim = true; + } - found = true; - break; + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + if(mAnimVelocity > 0.0f) break; } } - if(!found) + if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b60bd21a85..cd2523b634 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -54,7 +54,7 @@ protected: std::string mCurrentGroup; std::vector > *mCurrentControllers; - NifOgre::TextKeyMap *mCurrentKeys; + const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; @@ -65,7 +65,8 @@ protected: float mAnimVelocity; float mAnimSpeedMult; - void calcAnimVelocity(); + static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ From d936291dbf2b7c9e5240aad64b1d338aed2207df Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 02:53:32 -0700 Subject: [PATCH 0476/1537] Remove an unused ostream operator<< --- components/nifogre/ogrenifloader.cpp | 9 --------- components/nifogre/ogrenifloader.hpp | 10 ---------- 2 files changed, 19 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 97dfc59ef7..dc6bb8d246 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -44,15 +44,6 @@ #include "material.hpp" #include "mesh.hpp" -namespace std -{ - -// TODO: Do something useful -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&) -{ return o; } - -} - namespace NifOgre { diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index 8e220ea38d..d0ff942177 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -98,14 +98,4 @@ typedef Ogre::SharedPtr > NodeTargetValueRealPtr; } -namespace std -{ - -// These operators allow extra data types to be stored in an Ogre::Any -// object, which can then be stored in user object bindings on the nodes - -ostream& operator<<(ostream &o, const NifOgre::TextKeyMap&); - -} - #endif From 59137d93c99bdd9795a0dd0be7d3e9d4e63a2bb0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:24:02 -0700 Subject: [PATCH 0477/1537] Partially handle NiGeomMorpherController The morphs aren't actually applied yet, but the Ogre controller is set up so all that has to be done is to implement the setValue method. --- components/nifogre/mesh.cpp | 14 +++++++++ components/nifogre/ogrenifloader.cpp | 45 +++++++++++++++++++++++++++- components/nifogre/skeleton.cpp | 3 +- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c30..851160de2e 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -116,6 +116,20 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape std::vector srcNorms = data->normals; Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; bool vertShadowBuffer = false; + + if(!shape->controller.empty()) + { + Nif::ControllerPtr ctrl = shape->controller; + do { + if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; + vertShadowBuffer = true; + break; + } + } while(!(ctrl=ctrl->next).empty()); + } + if(skin != NULL) { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index dc6bb8d246..942b3858a7 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -293,7 +293,7 @@ public: } public: - Value(const Ogre::MaterialPtr &material, Nif::NiUVData *data) + Value(const Ogre::MaterialPtr &material, const Nif::NiUVData *data) : mMaterial(material) , mUTrans(data->mKeyList[0]) , mVTrans(data->mKeyList[1]) @@ -363,6 +363,36 @@ public: typedef DefaultFunction Function; }; +class GeomMorpherController +{ +public: + class Value : public Ogre::ControllerValue + { + private: + Ogre::SubEntity *mSubEntity; + std::vector mMorphs; + + public: + Value(Ogre::SubEntity *subent, const Nif::NiMorphData *data) + : mSubEntity(subent) + , mMorphs(data->mMorphs) + { } + + virtual Ogre::Real getValue() const + { + // Should not be called + return 0.0f; + } + + virtual void setValue(Ogre::Real value) + { + // TODO: Implement + } + }; + + typedef DefaultFunction Function; +}; + /** Object creator for NIFs. This is the main class responsible for creating * "live" Ogre objects (entities, particle systems, controllers, etc) from @@ -429,6 +459,19 @@ class NIFObjectLoader objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); } + else if(ctrl->recType == Nif::RC_NiGeomMorpherController) + { + const Nif::NiGeomMorpherController *geom = static_cast(ctrl.getPtr()); + + Ogre::SubEntity *subent = entity->getSubEntity(0); + Ogre::ControllerValueRealPtr srcval((animflags&Nif::NiNode::AnimFlag_AutoPlay) ? + Ogre::ControllerManager::getSingleton().getFrameTimeSource() : + Ogre::ControllerValueRealPtr()); + Ogre::ControllerValueRealPtr dstval(OGRE_NEW GeomMorpherController::Value(subent, geom->data.getPtr())); + Ogre::ControllerFunctionRealPtr func(OGRE_NEW GeomMorpherController::Function(geom, (animflags&Nif::NiNode::AnimFlag_AutoPlay))); + + objectlist.mControllers.push_back(Ogre::Controller(srcval, dstval, func)); + } ctrl = ctrl->next; } } diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1809212a78..1306d037c2 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -179,7 +179,8 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, ctrls.push_back(static_cast(ctrl.getPtr())); else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiGeomMorpherController )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; From adc6a948c7ed308c57c5996c57c8227c91d4af99 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 03:41:38 -0700 Subject: [PATCH 0478/1537] Add methods to get the rotation, translation, and scale from a NodeTargetValue --- components/nifogre/ogrenifloader.cpp | 41 ++++++++++++++++++++-------- components/nifogre/ogrenifloader.hpp | 4 ++- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 942b3858a7..451993cf4c 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -135,11 +135,14 @@ public: , mData(data->mVis) { } - virtual void applyToNode(Ogre::Node *node, float time) const - { - bool vis = calculate(time); - setVisible(node, vis); - } + virtual Ogre::Quaternion getRotation(float time) const + { return Ogre::Quaternion(); } + + virtual Ogre::Vector3 getTranslation(float time) const + { return Ogre::Vector3(0.0f); } + + virtual Ogre::Vector3 getScale(float time) const + { return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const { @@ -149,7 +152,8 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + bool vis = calculate(time); + setVisible(mNode, vis); } }; @@ -223,7 +227,7 @@ public: float a = (time-last->mTime) / (iter->mTime-last->mTime); return Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue); } - return Ogre::Quaternion(); + return keys.back().mValue; } public: @@ -234,14 +238,25 @@ public: , mScales(data->mScales) { } - virtual void applyToNode(Ogre::Node *node, float time) const + virtual Ogre::Quaternion getRotation(float time) const { if(mRotations.mKeys.size() > 0) - node->setOrientation(interpKey(mRotations.mKeys, time)); + return interpKey(mRotations.mKeys, time); + return Ogre::Quaternion(); + } + + virtual Ogre::Vector3 getTranslation(float time) const + { if(mTranslations.mKeys.size() > 0) - node->setPosition(interpKey(mTranslations.mKeys, time)); + return interpKey(mTranslations.mKeys, time); + return Ogre::Vector3(0.0f); + } + + virtual Ogre::Vector3 getScale(float time) const + { if(mScales.mKeys.size() > 0) - node->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); + return Ogre::Vector3(interpKey(mScales.mKeys, time)); + return Ogre::Vector3(1.0f); } virtual Ogre::Real getValue() const @@ -252,7 +267,9 @@ public: virtual void setValue(Ogre::Real time) { - Value::applyToNode(mNode, time); + mNode->setOrientation(Value::getRotation(time)); + mNode->setPosition(Value::getTranslation(time)); + mNode->setScale(Value::getScale(time)); } }; diff --git a/components/nifogre/ogrenifloader.hpp b/components/nifogre/ogrenifloader.hpp index d0ff942177..40577e4515 100644 --- a/components/nifogre/ogrenifloader.hpp +++ b/components/nifogre/ogrenifloader.hpp @@ -87,7 +87,9 @@ public: NodeTargetValue(Ogre::Node *target) : mNode(target) { } - virtual void applyToNode(Ogre::Node *node, float time) const = 0; + virtual Ogre::Quaternion getRotation(T value) const = 0; + virtual Ogre::Vector3 getTranslation(T value) const = 0; + virtual Ogre::Vector3 getScale(T value) const = 0; void setNode(Ogre::Node *target) { mNode = target; } From cc70c6263bf377f600d8af023985ec8a092c3f5a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 04:10:46 -0700 Subject: [PATCH 0479/1537] Use the NodeTargetValue for the NonAccum root --- apps/openmw/mwrender/animation.cpp | 114 ++++++++++------------------- apps/openmw/mwrender/animation.hpp | 4 +- 2 files changed, 42 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d71b33cddf..5700af3d6c 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -41,12 +41,12 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentAnim(NULL) , mCurrentControllers(NULL) , mCurrentKeys(NULL) , mCurrentTime(0.0f) , mPlaying(false) , mLooping(false) + , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -209,48 +209,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) { - const Ogre::NodeAnimationTrack *track = 0; - - Ogre::Animation::NodeTrackIterator trackiter = anim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) + const std::string loopstart = groupname+": loop start"; + const std::string loopstop = groupname+": loop stop"; + float loopstarttime = 0.0f; + float loopstoptime = std::numeric_limits::max(); + NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); + while(keyiter != keys->end()) { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == bonename) - track = cur; + if(keyiter->second == loopstart) + loopstarttime = keyiter->first; + else if(keyiter->second == loopstop) + { + loopstoptime = keyiter->first; + break; + } + keyiter++; } - if(track && track->getNumKeyFrames() > 1) + if(loopstoptime > loopstarttime) { - const std::string loopstart = groupname+": loop start"; - const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = anim->getLength(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) - { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) - { - loopstoptime = keyiter->first; - break; - } - keyiter++; - } + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); - if(loopstoptime > loopstarttime) - { - Ogre::TransformKeyFrame startkf(0, loopstarttime); - Ogre::TransformKeyFrame endkf(0, loopstoptime); - - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstarttime), &startkf); - track->getInterpolatedKeyFrame(anim->_getTimeIndex(loopstoptime), &endkf); - - return startkf.getTranslate().distance(endkf.getTranslate()) / - (loopstoptime-loopstarttime); - } + return startpos.distance(endpos) / (loopstoptime-loopstarttime); } return 0.0f; @@ -298,20 +281,8 @@ Ogre::Vector3 Animation::updatePosition() { Ogre::Vector3 posdiff; - Ogre::TransformKeyFrame kf(0, mCurrentTime); - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *track = trackiter.getNext(); - if(track->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - { - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - break; - } - } - /* Get the non-accumulation root's difference from the last update. */ - posdiff = (kf.getTranslate() - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -344,24 +315,9 @@ void Animation::reset(const std::string &start, const std::string &stop) mStopKey--; } - if(mNonAccumRoot) - { - const Ogre::NodeAnimationTrack *track = 0; - Ogre::Animation::NodeTrackIterator trackiter = mCurrentAnim->getNodeTrackIterator(); - while(!track && trackiter.hasMoreElements()) - { - const Ogre::NodeAnimationTrack *cur = trackiter.getNext(); - if(cur->getAssociatedNode()->getName() == mNonAccumRoot->getName()) - track = cur; - } - - if(track) - { - Ogre::TransformKeyFrame kf(0, mCurrentTime); - track->getInterpolatedKeyFrame(mCurrentAnim->_getTimeIndex(mCurrentTime), &kf); - mLastPosition = kf.getTranslate() * mAccumulate; - } - } + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * + mAccumulate; } @@ -431,24 +387,34 @@ void Animation::play(const std::string &groupname, const std::string &start, con { if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) { - Ogre::SkeletonInstance *skel = iter->mSkelBase->getSkeleton(); - Ogre::Animation *anim = skel->getAnimation(groupname); const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + if(!foundanim) { - mCurrentAnim = anim; mCurrentKeys = keys; mCurrentGroup = groupname; mCurrentControllers = &iter->mControllers; - + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; + foundanim = true; } if(!mNonAccumRoot) break; - mAnimVelocity = calcAnimVelocity(anim, mNonAccumRoot->getName(), groupname, keys); + mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); if(mAnimVelocity > 0.0f) break; } } @@ -469,7 +435,7 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) Ogre::Vector3 movement(0.0f); timepassed *= mAnimSpeedMult; - while(mCurrentAnim && mPlaying) + while(!mCurrentGroup.empty() && mPlaying) { float targetTime = mCurrentTime + timepassed; if(mNextKey->first > targetTime) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index cd2523b634..92f636d0ac 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -50,7 +50,6 @@ protected: Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - Ogre::Animation *mCurrentAnim; std::string mCurrentGroup; std::vector > *mCurrentControllers; @@ -62,10 +61,11 @@ protected: bool mPlaying; bool mLooping; + NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; - static float calcAnimVelocity(Ogre::Animation *anim, const std::string &bonename, + static float calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys); /* Updates a skeleton instance so that all bones matching the source skeleton (based on From bb64efc18e9252292b82f3540e487bb14b22901e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 05:08:52 -0700 Subject: [PATCH 0480/1537] Improve looping behavior --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 78 ++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 5 +- 3 files changed, 45 insertions(+), 40 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 16d8115284..4684ca6ea7 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "stop", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop); } CharacterController::CharacterController(const CharacterController &rhs) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 5700af3d6c..d065195ad5 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -293,36 +293,51 @@ Ogre::Vector3 Animation::updatePosition() void Animation::reset(const std::string &start, const std::string &stop) { + std::string tag = mCurrentGroup+": "+start; mStartKey = mCurrentKeys->begin(); - - while(mStartKey != mCurrentKeys->end() && mStartKey->second != start) + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) mStartKey++; - if(mStartKey != mCurrentKeys->end()) - mCurrentTime = mStartKey->first; - else + if(mStartKey == mCurrentKeys->end() && tag == "loop start") { + tag = mCurrentGroup+": start"; mStartKey = mCurrentKeys->begin(); - mCurrentTime = mStartKey->first; + while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) + mStartKey++; } - mNextKey = mStartKey; + if(mStartKey == mCurrentKeys->end()) + mStartKey = mCurrentKeys->begin(); - if(stop.length() > 0) - { - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != stop) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; - } + tag = mCurrentGroup+": "+stop; + mStopKey = mStartKey; + while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) + mStopKey++; + if(mStopKey == mCurrentKeys->end()) + mStopKey--; + + mCurrentTime = mStartKey->first; + mLoopStartKey = mStartKey; + mNextKey = mStartKey; + ++mNextKey; if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * - mAccumulate; + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; +} + +void Animation::doLoop() +{ + mCurrentTime = mLoopStartKey->first; + mNextKey = mLoopStartKey; + ++mNextKey; + if(mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; } -bool Animation::handleEvent(float time, const std::string &evt) +bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) { + float time = key->first; + const std::string &evt = key->second; + if(evt.compare(0, 7, "sound: ") == 0) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); @@ -347,25 +362,15 @@ bool Animation::handleEvent(float time, const std::string &evt) if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - /* Do nothing */ + mLoopStartKey = key; return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(mLooping) { - reset(mCurrentGroup+": loop start"); - if(mCurrentTime >= time) - return false; - return true; - } - } - else if(evt.compare(off, len, "stop") == 0) - { - if(mLooping) - { - reset(mCurrentGroup+": loop start"); + doLoop(); if(mCurrentTime >= time) return false; return true; @@ -421,7 +426,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - reset(mCurrentGroup+": "+start, mCurrentGroup+": "+stop); + reset(start, stop); setLooping(loop); mPlaying = true; } @@ -446,18 +451,15 @@ Ogre::Vector3 Animation::runAnimation(float timepassed) break; } - float time = mNextKey->first; - const std::string &evt = mNextKey->second; - mNextKey++; - - mCurrentTime = time; + NifOgre::TextKeyMap::const_iterator key(mNextKey++); + mCurrentTime = key->first; if(mNonAccumRoot) movement += updatePosition(); mPlaying = (mLooping || mStopKey->first > mCurrentTime); timepassed = targetTime - mCurrentTime; - if(!handleEvent(time, evt)) + if(!handleTextKey(key)) break; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 92f636d0ac..0d81cf3b4e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,6 +55,7 @@ protected: std::vector > *mCurrentControllers; const NifOgre::TextKeyMap *mCurrentKeys; NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; NifOgre::TextKeyMap::const_iterator mStopKey; NifOgre::TextKeyMap::const_iterator mNextKey; float mCurrentTime; @@ -82,7 +83,9 @@ protected: */ void reset(const std::string &start, const std::string &stop=std::string()); - bool handleEvent(float time, const std::string &evt); + void doLoop(); + + bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); From a2fc43c7df22786b4d022be550928c2478a16c24 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:41:54 -0700 Subject: [PATCH 0481/1537] Use reset to check that the animation exists and has the right markers --- apps/openmw/mwrender/animation.cpp | 123 ++++++++++++++++------------- apps/openmw/mwrender/animation.hpp | 10 ++- 2 files changed, 72 insertions(+), 61 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d065195ad5..a17d225e96 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -209,14 +209,14 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) } -float Animation::calcAnimVelocity(NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const NifOgre::TextKeyMap *keys) +float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; float loopstarttime = 0.0f; - float loopstoptime = std::numeric_limits::max(); - NifOgre::TextKeyMap::const_iterator keyiter = keys->begin(); - while(keyiter != keys->end()) + float loopstoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + while(keyiter != keys.end()) { if(keyiter->second == loopstart) loopstarttime = keyiter->first; @@ -291,36 +291,44 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -void Animation::reset(const std::string &start, const std::string &stop) +bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { - std::string tag = mCurrentGroup+": "+start; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; - if(mStartKey == mCurrentKeys->end() && tag == "loop start") + std::string tag = groupname+": "+start; + NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); + while(startkey != keys.end() && startkey->second != tag) + startkey++; + if(startkey == keys.end() && tag == "loop start") { - tag = mCurrentGroup+": start"; - mStartKey = mCurrentKeys->begin(); - while(mStartKey != mCurrentKeys->end() && mStartKey->second != tag) - mStartKey++; + tag = groupname+": start"; + startkey = keys.begin(); + while(startkey != keys.end() && startkey->second != tag) + startkey++; } - if(mStartKey == mCurrentKeys->end()) - mStartKey = mCurrentKeys->begin(); + if(startkey == keys.end()) + return false; - tag = mCurrentGroup+": "+stop; - mStopKey = mStartKey; - while(mStopKey != mCurrentKeys->end() && mStopKey->second != tag) - mStopKey++; - if(mStopKey == mCurrentKeys->end()) - mStopKey--; + tag = groupname+": "+stop; + NifOgre::TextKeyMap::const_iterator stopkey(startkey); + while(stopkey != keys.end() && stopkey->second != tag) + stopkey++; + if(stopkey == keys.end()) + return false; - mCurrentTime = mStartKey->first; + if(startkey == stopkey) + return false; + + mStartKey = startkey; mLoopStartKey = mStartKey; + mStopKey = stopkey; mNextKey = mStartKey; ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mCurrentTime = mStartKey->first; + + if(nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + + return true; } void Animation::doLoop() @@ -390,45 +398,46 @@ void Animation::play(const std::string &groupname, const std::string &start, con /* Look in reverse; last-inserted source has priority. */ for(std::vector::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(groupname)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + for(size_t i = 0;i < iter->mControllers.size();i++) { - const NifOgre::TextKeyMap *keys = &iter->mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - - if(!foundanim) - { - mCurrentKeys = keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - - foundanim = true; - } - - if(!mNonAccumRoot) + nonaccumctrl = dstval; break; - - mAnimVelocity = calcAnimVelocity(nonaccumctrl, groupname, keys); - if(mAnimVelocity > 0.0f) break; + } } + + if(!foundanim) + { + if(!reset(keys, nonaccumctrl, groupname, start, stop)) + continue; + mCurrentKeys = &keys; + mCurrentGroup = groupname; + mCurrentControllers = &iter->mControllers; + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + + setLooping(loop); + mPlaying = true; + + foundanim = true; + } + + if(!mNonAccumRoot) + break; + + mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); + if(mAnimVelocity > 0.0f) break; } if(!foundanim) throw std::runtime_error("Failed to find animation "+groupname); - - reset(start, stop); - setLooping(loop); - mPlaying = true; } catch(std::exception &e) { std::cerr<< e.what() < *nonaccumctrl, - const std::string &groupname, const NifOgre::TextKeyMap *keys); + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname); /* Updates a skeleton instance so that all bones matching the source skeleton (based on * bone names) are positioned identically. */ @@ -79,9 +80,10 @@ protected: /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If - * the marker is not found, it resets to the beginning or end respectively. + * the marker is not found, or if the markers are the same, it returns + * false. */ - void reset(const std::string &start, const std::string &stop=std::string()); + bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); void doLoop(); From 7279e015e9e76a0dec940f2f10fd2948c39500f5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 20:59:55 -0700 Subject: [PATCH 0482/1537] Search the textkeys to check if an animation group exists --- apps/openmw/mwrender/animation.cpp | 19 ++++++++++++++++++- apps/openmw/mwrender/animation.hpp | 2 ++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a17d225e96..b5f23b2c4e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -169,11 +169,28 @@ Ogre::Node *Animation::getNode(const std::string &name) } +NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname) +{ + NifOgre::TextKeyMap::const_iterator iter(keys.begin()); + for(;iter != keys.end();iter++) + { + if(iter->second.compare(0, groupname.size(), groupname) == 0 && + iter->second.compare(groupname.size(), 2, ": ") == 0) + break; + } + return iter; +} + + bool Animation::hasAnimation(const std::string &anim) { for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) { - if(iter->mSkelBase && iter->mSkelBase->hasAnimationState(anim)) + if(iter->mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + if(findGroupStart(keys, anim) != keys.end()) return true; } return false; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 06c2b485b9..6393ee7c91 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -78,6 +78,8 @@ protected: * returns the wanted movement vector from the previous update. */ Ogre::Vector3 updatePosition(); + static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); + /* Resets the animation to the time of the specified start marker, without * moving anything, and set the end time to the specified stop marker. If * the marker is not found, or if the markers are the same, it returns From c3ce49798a315c9fd8065b356f7fae87557c69cb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 21:34:39 -0700 Subject: [PATCH 0483/1537] Fix animation velocity calculation --- apps/openmw/mwrender/animation.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b5f23b2c4e..45f2a6fcb4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -228,29 +228,31 @@ void Animation::updatePtr(const MWWorld::Ptr &ptr) float Animation::calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname) { + const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; const std::string loopstop = groupname+": loop stop"; - float loopstarttime = 0.0f; - float loopstoptime = 0.0f; - NifOgre::TextKeyMap::const_iterator keyiter = keys.begin(); + const std::string stop = groupname+": stop"; + float starttime = std::numeric_limits::max(); + float stoptime = 0.0f; + NifOgre::TextKeyMap::const_iterator keyiter(keys.begin()); while(keyiter != keys.end()) { - if(keyiter->second == loopstart) - loopstarttime = keyiter->first; - else if(keyiter->second == loopstop) + if(keyiter->second == start || keyiter->second == loopstart) + starttime = keyiter->first; + else if(keyiter->second == loopstop || keyiter->second == stop) { - loopstoptime = keyiter->first; + stoptime = keyiter->first; break; } keyiter++; } - if(loopstoptime > loopstarttime) + if(stoptime > starttime) { - Ogre::Vector3 startpos = nonaccumctrl->getTranslation(loopstarttime); - Ogre::Vector3 endpos = nonaccumctrl->getTranslation(loopstarttime); + Ogre::Vector3 startpos = nonaccumctrl->getTranslation(starttime); + Ogre::Vector3 endpos = nonaccumctrl->getTranslation(stoptime); - return startpos.distance(endpos) / (loopstoptime-loopstarttime); + return startpos.distance(endpos) / (stoptime-starttime); } return 0.0f; From 8782ae6976aa316a5394dd4e33c6cf0cd290779a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 22 Apr 2013 23:35:50 -0700 Subject: [PATCH 0484/1537] Separate some Animation fields into a separate AnimLayer class --- apps/openmw/mwmechanics/character.cpp | 4 - apps/openmw/mwrender/animation.cpp | 179 +++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 52 ++++---- 3 files changed, 130 insertions(+), 105 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4684ca6ea7..07f7b69401 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -304,11 +304,7 @@ void CharacterController::skipAnim() void CharacterController::setState(CharacterState state, bool loop) { if(mState == state) - { - if(mAnimation) - mAnimation->setLooping(loop); return; - } mState = state; if(!mAnimation) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 45f2a6fcb4..4c5a869856 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -18,6 +18,32 @@ namespace MWRender { +Animation::AnimLayer::AnimLayer() + : mControllers(NULL) + , mTextKeys(NULL) + , mTime(0.0f) + , mPlaying(false) + , mLooping(false) +{ +} + + +Ogre::Real Animation::AnimationValue::getValue() const +{ + size_t idx = mIndex; + while(idx > 0 && mAnimation->mLayer[idx].mGroupName.empty()) + idx--; + if(!mAnimation->mLayer[idx].mGroupName.empty()) + return mAnimation->mLayer[idx].mTime; + return 0.0f; +} + +void Animation::AnimationValue::setValue(Ogre::Real value) +{ + mAnimation->mLayer[mIndex].mTime = value; +} + + void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects) { for(size_t i = 0;i < objects.mParticles.size();i++) @@ -32,7 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this)) + : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) , mPtr(ptr) , mController(NULL) , mInsert(NULL) @@ -41,11 +67,6 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mNonAccumRoot(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mCurrentControllers(NULL) - , mCurrentKeys(NULL) - , mCurrentTime(0.0f) - , mPlaying(false) - , mLooping(false) , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) @@ -127,9 +148,6 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } - - if(!mCurrentControllers || (*mCurrentControllers).size() == 0) - mCurrentControllers = &objlist.mControllers; } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -215,10 +233,6 @@ void Animation::setSpeed(float speed) mAnimSpeedMult = speed / mAnimVelocity; } -void Animation::setLooping(bool loop) -{ - mLooping = loop; -} void Animation::updatePtr(const MWWorld::Ptr &ptr) { @@ -301,7 +315,7 @@ Ogre::Vector3 Animation::updatePosition() Ogre::Vector3 posdiff; /* Get the non-accumulation root's difference from the last update. */ - posdiff = (mNonAccumCtrl->getTranslation(mCurrentTime) - mLastPosition) * mAccumulate; + posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; @@ -310,7 +324,7 @@ Ogre::Vector3 Animation::updatePosition() return posdiff; } -bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -336,31 +350,31 @@ bool Animation::reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue< if(startkey == stopkey) return false; - mStartKey = startkey; - mLoopStartKey = mStartKey; - mStopKey = stopkey; - mNextKey = mStartKey; - ++mNextKey; + mLayer[layeridx].mStartKey = startkey; + mLayer[layeridx].mLoopStartKey = startkey; + mLayer[layeridx].mStopKey = stopkey; + mLayer[layeridx].mNextKey = startkey; + mLayer[layeridx].mNextKey++; - mCurrentTime = mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; - if(nonaccumctrl) - mLastPosition = nonaccumctrl->getTranslation(mCurrentTime) * mAccumulate; + if(layeridx == 0 && nonaccumctrl) + mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; return true; } -void Animation::doLoop() +void Animation::doLoop(size_t layeridx) { - mCurrentTime = mLoopStartKey->first; - mNextKey = mLoopStartKey; - ++mNextKey; - if(mNonAccumCtrl) - mLastPosition = mNonAccumCtrl->getTranslation(mCurrentTime) * mAccumulate; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; + mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; + mLayer[layeridx].mNextKey++; + if(layeridx == 0 && mNonAccumCtrl) + mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } -bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) +bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key) { float time = key->first; const std::string &evt = key->second; @@ -378,27 +392,27 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) return true; } - if(evt.compare(0, mCurrentGroup.size(), mCurrentGroup) != 0 || - evt.compare(mCurrentGroup.size(), 2, ": ") != 0) + if(evt.compare(0, mLayer[layeridx].mGroupName.size(), mLayer[layeridx].mGroupName) != 0 || + evt.compare(mLayer[layeridx].mGroupName.size(), 2, ": ") != 0) { - // Not ours + // Not ours, skip it return true; } - size_t off = mCurrentGroup.size()+2; + size_t off = mLayer[layeridx].mGroupName.size()+2; size_t len = evt.size() - off; if(evt.compare(off, len, "start") == 0 || evt.compare(off, len, "loop start") == 0) { - mLoopStartKey = key; + mLayer[layeridx].mLoopStartKey = key; return true; } if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLooping) + if(mLayer[layeridx].mLooping) { - doLoop(); - if(mCurrentTime >= time) + doLoop(layeridx); + if(mLayer[layeridx].mTime >= time) return false; return true; } @@ -412,6 +426,9 @@ bool Animation::handleTextKey(const NifOgre::TextKeyMap::const_iterator &key) void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) { + // TODO: parameterize this + size_t layeridx = 0; + try { bool foundanim = false; /* Look in reverse; last-inserted source has priority. */ @@ -422,34 +439,40 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - for(size_t i = 0;i < iter->mControllers.size();i++) + if(layeridx == 0) { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) + for(size_t i = 0;i < iter->mControllers.size();i++) { - nonaccumctrl = dstval; - break; + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } } } if(!foundanim) { - if(!reset(keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) continue; - mCurrentKeys = &keys; - mCurrentGroup = groupname; - mCurrentControllers = &iter->mControllers; - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; - setLooping(loop); - mPlaying = true; + if(layeridx == 0) + { + mNonAccumCtrl = nonaccumctrl; + mAnimVelocity = 0.0f; + } foundanim = true; } - if(!mNonAccumRoot) + if(!nonaccumctrl) break; mAnimVelocity = calcAnimVelocity(keys, nonaccumctrl, groupname); @@ -463,37 +486,43 @@ void Animation::play(const std::string &groupname, const std::string &start, con } } -Ogre::Vector3 Animation::runAnimation(float timepassed) +Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - timepassed *= mAnimSpeedMult; - while(!mCurrentGroup.empty() && mPlaying) + duration *= mAnimSpeedMult; + for(size_t layeridx = 0;layeridx < sMaxLayers;layeridx++) { - float targetTime = mCurrentTime + timepassed; - if(mNextKey->first > targetTime) + if(mLayer[layeridx].mGroupName.empty()) + continue; + + float timepassed = duration; + while(mLayer[layeridx].mPlaying) { - mCurrentTime = targetTime; - if(mNonAccumRoot) + float targetTime = mLayer[layeridx].mTime + timepassed; + if(mLayer[layeridx].mNextKey->first > targetTime) + { + mLayer[layeridx].mTime = targetTime; + if(layeridx == 0 && mNonAccumRoot) + movement += updatePosition(); + break; + } + + NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); + mLayer[layeridx].mTime = key->first; + if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - break; + + mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + timepassed = targetTime - mLayer[layeridx].mTime; + + if(!handleTextKey(layeridx, key)) + break; } - - NifOgre::TextKeyMap::const_iterator key(mNextKey++); - mCurrentTime = key->first; - if(mNonAccumRoot) - movement += updatePosition(); - - mPlaying = (mLooping || mStopKey->first > mCurrentTime); - timepassed = targetTime - mCurrentTime; - - if(!handleTextKey(key)) - break; + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); } - for(size_t i = 0;i < (*mCurrentControllers).size();i++) - (*mCurrentControllers)[i].update(); - if(mSkelBase) { const Ogre::SkeletonInstance *baseinst = mSkelBase->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 6393ee7c91..96138cf749 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -23,20 +23,15 @@ protected: { private: Animation *mAnimation; + size_t mIndex; public: - AnimationValue(Animation *anim) : mAnimation(anim) + AnimationValue(Animation *anim, size_t layeridx) + : mAnimation(anim), mIndex(layeridx) { } - virtual Ogre::Real getValue() const - { - return mAnimation->mCurrentTime; - } - - virtual void setValue(Ogre::Real value) - { - mAnimation->mCurrentTime = value; - } + virtual Ogre::Real getValue() const; + virtual void setValue(Ogre::Real value); }; Ogre::SharedPtr > mAnimationBaseValuePtr; @@ -51,21 +46,28 @@ protected: Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - std::string mCurrentGroup; - std::vector > *mCurrentControllers; - const NifOgre::TextKeyMap *mCurrentKeys; - NifOgre::TextKeyMap::const_iterator mStartKey; - NifOgre::TextKeyMap::const_iterator mLoopStartKey; - NifOgre::TextKeyMap::const_iterator mStopKey; - NifOgre::TextKeyMap::const_iterator mNextKey; - float mCurrentTime; - bool mPlaying; - bool mLooping; - NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + static const size_t sMaxLayers = 1; + struct AnimLayer { + std::string mGroupName; + std::vector > *mControllers; + const NifOgre::TextKeyMap *mTextKeys; + NifOgre::TextKeyMap::const_iterator mStartKey; + NifOgre::TextKeyMap::const_iterator mLoopStartKey; + NifOgre::TextKeyMap::const_iterator mStopKey; + NifOgre::TextKeyMap::const_iterator mNextKey; + + float mTime; + + bool mPlaying; + bool mLooping; + + AnimLayer(); + } mLayer[sMaxLayers]; + static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname); @@ -85,11 +87,11 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(); + void doLoop(size_t layeridx); - bool handleTextKey(const NifOgre::TextKeyMap::const_iterator &key); + bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); void addObjectList(Ogre::SceneNode *node, const std::string &model, bool baseonly); static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects); @@ -113,8 +115,6 @@ public: void setSpeed(float speed); - void setLooping(bool loop); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); virtual Ogre::Vector3 runAnimation(float timepassed); From e3781769371e8c736bcf2643537c60cf6fe106f2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 00:15:31 -0700 Subject: [PATCH 0485/1537] Don't update controllers that have already been updated --- apps/openmw/mwrender/animation.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4c5a869856..0166eb8436 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -519,8 +519,23 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(!handleTextKey(layeridx, key)) break; } - for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) - (*(mLayer[layeridx].mControllers))[i].update(); + + bool updatectrls = true; + for(size_t i = layeridx-1;i < layeridx;i--) + { + if(mLayer[i].mGroupName.empty()) + continue; + if(mLayer[i].mControllers == mLayer[layeridx].mControllers) + { + updatectrls = false; + break; + } + } + if(updatectrls) + { + for(size_t i = 0;i < (*(mLayer[layeridx].mControllers)).size();i++) + (*(mLayer[layeridx].mControllers))[i].update(); + } } if(mSkelBase) From afe7b3c64c4adafd112b4d151d8866ffefb4a725 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 10:56:55 +0200 Subject: [PATCH 0486/1537] added additional type argument to IdCollection::appendBlankRecord --- apps/opencs/model/world/idcollection.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 7052b300e4..45b4961aab 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -16,6 +16,7 @@ #include #include "columnbase.hpp" +#include "universalid.hpp" namespace CSMWorld { @@ -53,7 +54,9 @@ namespace CSMWorld virtual void removeRows (int index, int count) = 0; - virtual void appendBlankRecord (const std::string& id) = 0; + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None) = 0; + ///< \param type Will be ignored, unless the collection supports multiple record types virtual int searchId (const std::string& id) const = 0; ////< Search record with \a id. @@ -143,7 +146,9 @@ namespace CSMWorld virtual void removeRows (int index, int count) ; - virtual void appendBlankRecord (const std::string& id); + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types virtual int searchId (const std::string& id) const; ////< Search record with \a id. @@ -300,7 +305,8 @@ namespace CSMWorld } template - void IdCollection::appendBlankRecord (const std::string& id) + void IdCollection::appendBlankRecord (const std::string& id, + UniversalId::Type type) { ESXRecordT record; IdAccessorT().getId (record) = id; From 808718d96708d9833e7a8fe959de1e8823802039 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 11:21:21 +0200 Subject: [PATCH 0487/1537] added referenceable record types to UniversalId --- apps/opencs/model/world/universalid.cpp | 26 +++++++++++++++++++++++++ apps/opencs/model/world/universalid.hpp | 25 +++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index c0241bc383..bd1632e3e7 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -29,6 +29,8 @@ namespace { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells" }, + { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables, + "Referenceables" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; @@ -47,6 +49,30 @@ namespace { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Activator, "Activator" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Potion, "Potion" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Apparatus, "Apparatus" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Armor, "Armor" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Book, "Book" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Clothing, "Clothing" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Container, "Container" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Creature, "Creature" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Door, "Door" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Ingredient, "Ingredient" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_CreatureLevelledList, + "Creature Levelled List" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_ItemLevelledList, + "Item Levelled List" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Light, "Light" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Lockpick, "Lockpick" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Miscellaneous, + "Miscellaneous" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Npc, "NPC" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Probe, "Probe" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Repair, "Repair" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Static, "Static" }, + { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Weapon, "Weapon" }, { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 9b52aded1f..2c4b14eaf5 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -57,7 +57,30 @@ namespace CSMWorld Type_Spells, Type_Spell, Type_Cells, - Type_Cell + Type_Cell, + Type_Referenceables, + Type_Referenceable, + Type_Activator, + Type_Potion, + Type_Apparatus, + Type_Armor, + Type_Book, + Type_Clothing, + Type_Container, + Type_Creature, + Type_Door, + Type_Ingredient, + Type_CreatureLevelledList, + Type_ItemLevelledList, + Type_Light, + Type_Lockpick, + Type_Miscellaneous, + Type_Npc, + Type_Probe, + Type_Repair, + Type_Static, + Type_Weapon + }; private: From a17d17c19105557c88ff2cdcaca19df103f6fba6 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 23 Apr 2013 11:22:07 +0200 Subject: [PATCH 0488/1537] added additional type argument to IdCollection::load --- apps/opencs/model/world/idcollection.hpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 45b4961aab..7761929f3f 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -79,7 +79,9 @@ namespace CSMWorld virtual const RecordBase& getRecord (int index) const = 0; - virtual void load (ESM::ESMReader& reader, bool base) = 0; + virtual void load (ESM::ESMReader& reader, bool base, + UniversalId::Type type = UniversalId::Type_None) = 0; + ///< \param type Will be ignored, unless the collection supports multiple record types }; ///< \brief Access to ID field in records @@ -171,7 +173,9 @@ namespace CSMWorld virtual const Record& getRecord (int index) const; - virtual void load (ESM::ESMReader& reader, bool base); + virtual void load (ESM::ESMReader& reader, bool base, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types void addColumn (Column *column); }; @@ -348,7 +352,8 @@ namespace CSMWorld } template - void IdCollection::load (ESM::ESMReader& reader, bool base) + void IdCollection::load (ESM::ESMReader& reader, bool base, + UniversalId::Type type) { std::string id = reader.getHNOString ("NAME"); From e4c5aac9664db105fde2b31b0973d5c7b483d80a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 02:48:11 -0700 Subject: [PATCH 0489/1537] Keep track of the animation layers a given object list is animating on This only tracks layers they explicitly animate on. They may animate on other layers as well, if nothing else is animating on them. --- apps/openmw/mwrender/activatoranimation.cpp | 2 +- apps/openmw/mwrender/animation.cpp | 63 +++++++++++++++------ apps/openmw/mwrender/animation.hpp | 11 +++- apps/openmw/mwrender/creatureanimation.cpp | 2 +- 4 files changed, 58 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwrender/activatoranimation.cpp b/apps/openmw/mwrender/activatoranimation.cpp index c3a3045c20..4eb844607c 100644 --- a/apps/openmw/mwrender/activatoranimation.cpp +++ b/apps/openmw/mwrender/activatoranimation.cpp @@ -22,7 +22,7 @@ ActivatorAnimation::ActivatorAnimation(const MWWorld::Ptr &ptr) const std::string name = "meshes\\"+ref->mBase->mModel; addObjectList(mPtr.getRefData().getBaseNode(), name, false); - setRenderProperties(mObjectLists.back(), RV_Misc, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Misc, RQG_Main, RQG_Alpha); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 0166eb8436..98e2f91043 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -78,9 +78,9 @@ Animation::~Animation() if(mInsert) { Ogre::SceneManager *sceneMgr = mInsert->getCreator(); - for(size_t i = 0;i < mObjectLists.size();i++) - destroyObjectList(sceneMgr, mObjectLists[i]); - mObjectLists.clear(); + for(size_t i = 0;i < mObjects.size();i++) + destroyObjectList(sceneMgr, mObjects[i].mObjectList); + mObjects.clear(); } } @@ -93,9 +93,13 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b assert(mInsert); } - mObjectLists.push_back(!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : - NifOgre::Loader::createObjectBase(mInsert, model)); - NifOgre::ObjectList &objlist = mObjectLists.back(); + mObjects.push_back(ObjectInfo()); + ObjectInfo &obj = mObjects.back(); + obj.mActiveLayers = 0; + obj.mObjectList = (!baseonly ? NifOgre::Loader::createObjects(mInsert, model) : + NifOgre::Loader::createObjectBase(mInsert, model)); + + NifOgre::ObjectList &objlist = obj.mObjectList; if(objlist.mSkelBase) { if(!mSkelBase) @@ -202,12 +206,12 @@ NifOgre::TextKeyMap::const_iterator Animation::findGroupStart(const NifOgre::Tex bool Animation::hasAnimation(const std::string &anim) { - for(std::vector::const_iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::const_iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - if(iter->mTextKeys.size() == 0) + if(iter->mObjectList.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = iter->mObjectList.mTextKeys.begin()->second; if(findGroupStart(keys, anim) != keys.end()) return true; } @@ -430,21 +434,45 @@ void Animation::play(const std::string &groupname, const std::string &start, con size_t layeridx = 0; try { + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjectLists.rbegin());iter != mObjectLists.rend();iter++) + for(std::vector::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) { - if(iter->mTextKeys.size() == 0) + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) continue; - const NifOgre::TextKeyMap &keys = iter->mTextKeys.begin()->second; + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; if(layeridx == 0) { - for(size_t i = 0;i < iter->mControllers.size();i++) + for(size_t i = 0;i < objlist.mControllers.size();i++) { NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(iter->mControllers[i].getDestination().getPointer()); + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); if(dstval && dstval->getNode() == mNonAccumRoot) { nonaccumctrl = dstval; @@ -459,7 +487,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &iter->mControllers; + mLayer[layeridx].mControllers = &objlist.mControllers; mLayer[layeridx].mLooping = loop; mLayer[layeridx].mPlaying = true; @@ -469,6 +497,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mAnimVelocity = 0.0f; } + iter->mActiveLayers |= (1<getSkeleton(); - for(std::vector::iterator iter(mObjectLists.begin());iter != mObjectLists.end();iter++) + for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) { - Ogre::Entity *ent = iter->mSkelBase; + Ogre::Entity *ent = iter->mObjectList.mSkelBase; if(!ent) continue; Ogre::SkeletonInstance *inst = ent->getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 96138cf749..840c22ae47 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -38,9 +38,18 @@ protected: MWWorld::Ptr mPtr; MWMechanics::CharacterController *mController; + struct ObjectInfo { + NifOgre::ObjectList mObjectList; + /* Bit-field specifying which animation layers this object list is + * explicitly animating on (1 = layer 0, 2 = layer 1, 4 = layer 2. + * etc). + */ + int mActiveLayers; + }; + Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; - std::vector mObjectLists; + std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; Ogre::Vector3 mAccumulate; diff --git a/apps/openmw/mwrender/creatureanimation.cpp b/apps/openmw/mwrender/creatureanimation.cpp index 51632b2ee1..97c28c0ae4 100644 --- a/apps/openmw/mwrender/creatureanimation.cpp +++ b/apps/openmw/mwrender/creatureanimation.cpp @@ -25,7 +25,7 @@ CreatureAnimation::CreatureAnimation(const MWWorld::Ptr &ptr) addObjectList(mPtr.getRefData().getBaseNode(), "meshes\\base_anim.nif", true); addObjectList(mPtr.getRefData().getBaseNode(), model, false); - setRenderProperties(mObjectLists.back(), RV_Actors, RQG_Main, RQG_Alpha); + setRenderProperties(mObjects.back().mObjectList, RV_Actors, RQG_Main, RQG_Alpha); } } From cfccf0981dee740e725eb819d1dbb2cf00c66b2d Mon Sep 17 00:00:00 2001 From: greye Date: Tue, 23 Apr 2013 13:24:06 +0400 Subject: [PATCH 0490/1537] update IndexedStore::setUp() for multiple datafile support --- apps/openmw/mwworld/store.hpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fb3f8c4826..959b944e10 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -872,7 +872,28 @@ namespace MWWorld } void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); + /// \note This method sorts indexed values for further + /// searches. Every loaded item is present in storage, but + /// latest loaded shadows any previous while searching. + /// If memory cost will be too high, it is possible to remove + /// unused values. + + Compare cmp; + + std::stable_sort(mStatic.begin(), mStatic.end(), cmp); + + typename std::vector::iterator first, next; + next = first = mStatic.begin(); + + while (first != mStatic.end() && ++next != mStatic.end()) { + while (next != mStatic.end() && !cmp(*first, *next)) { + ++next; + } + if (first != --next) { + std::swap(*first, *next); + } + first = ++next; + } } const T *search(int index) const { From c4806f01f850bbf18052659e45b222553b9f747c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 03:42:00 -0700 Subject: [PATCH 0491/1537] Use a separate list of controllers to update This should make it easier to figure out what controllers need to be updated for various animation sources and layers. --- apps/openmw/mwrender/animation.cpp | 220 ++++++++++++++++++----------- apps/openmw/mwrender/animation.hpp | 3 + 2 files changed, 139 insertions(+), 84 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 98e2f91043..fbf5725c46 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -71,6 +71,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + /* As long as we remain under 128 active controllers, we can avoid + * reallocations. */ + mActiveCtrls.reserve(128); } Animation::~Animation() @@ -179,6 +182,79 @@ void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::ui } +void Animation::updateActiveControllers() +{ + mActiveCtrls.clear(); + + /* First, get all controllers that don't target a node, or that target + * nodes that don't belong to any particular layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + std::vector >::const_iterator ctrl(obj->mObjectList.mControllers.begin()); + for(;ctrl != obj->mObjectList.mControllers.end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*if(getLayerByName(dstval->getNode()->getName()) >= 0)*/ + continue; + } + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + std::vector > *ctrls = NULL; + size_t layer = 0; + while(layer < sMaxLayers) + { + /* Now get controllers that target nodes that belong to this layer from + * whatever objectlist is active on this layer. + */ + std::vector::iterator obj(mObjects.begin()); + for(;obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1<mObjectList.mControllers; + break; + } + } + + /* Check if any objectlists are active on subsequent layers. Include + * those layers if not. + */ + size_t nextlayer = layer+1; + for(;nextlayer < sMaxLayers;nextlayer++) + { + for(obj = mObjects.begin();obj != mObjects.end();obj++) + { + if((obj->mActiveLayers&(1< >::const_iterator ctrl(ctrls->begin()); + for(;ctrl != ctrls->end();ctrl++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(ctrl->getDestination().getPointer()); + if(dstval) + { + /*ssize_t idx = getLayerByName(dstval->getNode()->getName()); + if(idx >= (ssize_t)layer && idx < (ssize_t)nextlayer)*/ + mActiveCtrls.insert(mActiveCtrls.end(), *ctrl); + } + } + + layer = nextlayer; + } +} + + Ogre::Node *Animation::getNode(const std::string &name) { if(mSkelBase) @@ -433,86 +509,76 @@ void Animation::play(const std::string &groupname, const std::string &start, con // TODO: parameterize this size_t layeridx = 0; - try { - for(std::vector::iterator iter(mObjects.begin());iter != mObjects.end();iter++) - iter->mActiveLayers &= ~(1<::iterator iter(mObjects.begin());iter != mObjects.end();iter++) + iter->mActiveLayers &= ~(1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) + { + NifOgre::ObjectList &objlist = iter->mObjectList; + if(objlist.mTextKeys.size() == 0) + continue; + + const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; + NifOgre::NodeTargetValue *nonaccumctrl = NULL; + if(layeridx == 0) { - // Do not allow layer 0 to be disabled - assert(layeridx != 0); + for(size_t i = 0;i < objlist.mControllers.size();i++) + { + NifOgre::NodeTargetValue *dstval; + dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); + if(dstval && dstval->getNode() == mNonAccumRoot) + { + nonaccumctrl = dstval; + break; + } + } + } - mLayer[layeridx].mGroupName.clear(); - mLayer[layeridx].mTextKeys = NULL; - mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; - mLayer[layeridx].mPlaying = false; + if(!foundanim) + { + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + continue; + mLayer[layeridx].mGroupName = groupname; + mLayer[layeridx].mTextKeys = &keys; + mLayer[layeridx].mControllers = &objlist.mControllers; + mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mPlaying = true; if(layeridx == 0) { - mNonAccumCtrl = NULL; + mNonAccumCtrl = nonaccumctrl; mAnimVelocity = 0.0f; } - return; + iter->mActiveLayers |= (1<::reverse_iterator iter(mObjects.rbegin());iter != mObjects.rend();iter++) - { - NifOgre::ObjectList &objlist = iter->mObjectList; - if(objlist.mTextKeys.size() == 0) - continue; + if(!nonaccumctrl) + break; - const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; - NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) - { - for(size_t i = 0;i < objlist.mControllers.size();i++) - { - NifOgre::NodeTargetValue *dstval; - dstval = dynamic_cast*>(objlist.mControllers[i].getDestination().getPointer()); - if(dstval && dstval->getNode() == mNonAccumRoot) - { - nonaccumctrl = dstval; - break; - } - } - } - - if(!foundanim) - { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) - continue; - mLayer[layeridx].mGroupName = groupname; - mLayer[layeridx].mTextKeys = &keys; - mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; - mLayer[layeridx].mPlaying = true; - - if(layeridx == 0) - { - mNonAccumCtrl = nonaccumctrl; - mAnimVelocity = 0.0f; - } - - iter->mActiveLayers |= (1< 0.0f) break; - } - if(!foundanim) - throw std::runtime_error("Failed to find animation "+groupname); - } - catch(std::exception &e) { - std::cerr<< e.what() < 0.0f) break; } + if(!foundanim) + std::cerr<< "Failed to find animation "<getSkeleton(); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 840c22ae47..4860f44f5c 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -58,6 +58,7 @@ protected: NifOgre::NodeTargetValue *mNonAccumCtrl; float mAnimVelocity; float mAnimSpeedMult; + std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; struct AnimLayer { @@ -107,6 +108,8 @@ protected: static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue); + void updateActiveControllers(); + public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); From 8c9e2e0ee9e24b444efa67f811ed8be1cd87fbcb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 05:34:08 -0700 Subject: [PATCH 0492/1537] Improve handling of reaching the stop animation text key --- apps/openmw/mwrender/animation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index fbf5725c46..d98a32828a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -449,6 +449,7 @@ void Animation::doLoop(size_t layeridx) mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; + mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; } @@ -608,7 +609,7 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(layeridx == 0 && mNonAccumRoot) movement += updatePosition(); - mLayer[layeridx].mPlaying = (mLayer[layeridx].mLooping || mLayer[layeridx].mStopKey->first > mLayer[layeridx].mTime); + mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; if(!handleTextKey(layeridx, key)) From 44ac0a7c1856bf463f18ed435d554574745d4c50 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 0493/1537] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c30..6d940deed3 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 634b0fd067a7c4ac65123be69dd29c0c4739be2f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 17:57:40 -0700 Subject: [PATCH 0494/1537] Fix for controller delta time going below start time --- components/nifogre/ogrenifloader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 451993cf4c..95ba439d1b 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -65,11 +65,7 @@ public: , mStopTime(ctrl->timeStop) { if(mDeltaInput) - { mDeltaCount = mPhase; - while(mDeltaCount < mStartTime) - mDeltaCount += (mStopTime-mStartTime); - } } virtual Ogre::Real calculate(Ogre::Real value) @@ -77,6 +73,9 @@ public: if(mDeltaInput) { mDeltaCount += value*mFrequency; + if(mDeltaCount < mStartTime) + mDeltaCount = mStopTime - std::fmod(mStartTime - mDeltaCount, + mStopTime - mStartTime); mDeltaCount = std::fmod(mDeltaCount - mStartTime, mStopTime - mStartTime) + mStartTime; return mDeltaCount; From 7e2995bc2f7b21f2335424e0d49e7d5231a673d7 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 19:43:26 -0700 Subject: [PATCH 0495/1537] Fix setting up active controllers --- apps/openmw/mwrender/animation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index d98a32828a..cb54a03665 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -155,6 +155,8 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b if(objlist.mControllers[i].getSource().isNull()) objlist.mControllers[i].setSource(mAnimationBaseValuePtr); } + + mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); } void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue) @@ -231,7 +233,7 @@ void Animation::updateActiveControllers() { for(obj = mObjects.begin();obj != mObjects.end();obj++) { - if((obj->mActiveLayers&(1<mActiveLayers&(1< Date: Tue, 23 Apr 2013 20:42:54 -0700 Subject: [PATCH 0496/1537] Don't create Ogre animations for skeletons --- components/nifogre/ogrenifloader.cpp | 28 +++- components/nifogre/skeleton.cpp | 220 ++------------------------- components/nifogre/skeleton.hpp | 4 +- 3 files changed, 37 insertions(+), 215 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 95ba439d1b..e451326fee 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,6 +676,32 @@ class NIFObjectLoader } + static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + { + TextKeyMap textkeys; + for(size_t i = 0;i < tk->list.size();i++) + { + const std::string &str = tk->list[i].text; + std::string::size_type pos = 0; + while(pos < str.length()) + { + if(::isspace(str[pos])) + { + pos++; + continue; + } + + std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); + std::string result = str.substr(pos, nextpos-pos); + textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); + + pos = nextpos; + } + } + return textkeys; + } + + static void createObjects(const std::string &name, const std::string &group, Ogre::SceneManager *sceneMgr, const Nif::Node *node, ObjectList &objectlist, int flags, int animflags, int partflags) @@ -704,7 +730,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = NIFSkeletonLoader::extractTextKeys(tk); + objectlist.mTextKeys[trgtid] = extractTextKeys(tk); } else if(e->recType == Nif::RC_NiStringExtraData) { diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index 1306d037c2..3aec920fc4 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -11,142 +11,7 @@ namespace NifOgre { -void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) -{ - Ogre::Animation *anim = skel->createAnimation(name, stopTime); - - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *kfc = ctrls[i]; - if(kfc->data.empty()) - continue; - const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - - Ogre::Bone *bone = skel->getBone(targets[i]); - // NOTE: For some reason, Ogre doesn't like the node track ID being different from - // the bone ID - Ogre::NodeAnimationTrack *nodetrack = anim->hasNodeTrack(bone->getHandle()) ? - anim->getNodeTrack(bone->getHandle()) : - anim->createNodeTrack(bone->getHandle(), bone); - - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); - - bool didlast = false; - while(!didlast) - { - float curtime = std::numeric_limits::max(); - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } - - Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } - } - } - anim->optimise(); -} - - -TextKeyMap NIFSkeletonLoader::extractTextKeys(const Nif::NiTextKeyExtraData *tk) -{ - TextKeyMap textkeys; - for(size_t i = 0;i < tk->list.size();i++) - { - const std::string &str = tk->list[i].text; - std::string::size_type pos = 0; - while(pos < str.length()) - { - if(::isspace(str[pos])) - { - pos++; - continue; - } - - std::string::size_type nextpos = std::min(str.find('\r', pos), str.find('\n', pos)); - std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::toLower(result))); - - pos = nextpos; - } - } - return textkeys; -} - -void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent) +void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent) { Ogre::Bone *bone; if(!skel->hasBone(node->name)) @@ -175,29 +40,16 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Nif::ControllerPtr ctrl = node->controller; while(!ctrl.empty()) { - if(ctrl->recType == Nif::RC_NiKeyframeController) - ctrls.push_back(static_cast(ctrl.getPtr())); - else if(!(ctrl->recType == Nif::RC_NiParticleSystemController || - ctrl->recType == Nif::RC_NiVisController || - ctrl->recType == Nif::RC_NiUVController || - ctrl->recType == Nif::RC_NiGeomMorpherController - )) + if(!(ctrl->recType == Nif::RC_NiParticleSystemController || + ctrl->recType == Nif::RC_NiVisController || + ctrl->recType == Nif::RC_NiUVController || + ctrl->recType == Nif::RC_NiKeyframeController || + ctrl->recType == Nif::RC_NiGeomMorpherController + )) warn("Unhandled "+ctrl->recName+" from node "+node->name+" in "+skel->getName()); ctrl = ctrl->next; } - Nif::ExtraPtr e = node->extra; - while(!e.empty()) - { - if(e->recType == Nif::RC_NiTextKeyExtraData && !animroot) - { - const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); - textkeys = extractTextKeys(tk); - animroot = bone; - } - e = e->extra; - } - const Nif::NiNode *ninode = dynamic_cast(node); if(ninode) { @@ -205,7 +57,7 @@ void NIFSkeletonLoader::buildBones(Ogre::Skeleton *skel, const Nif::Node *node, for(size_t i = 0;i < children.length();i++) { if(!children[i].empty()) - buildBones(skel, children[i].getPtr(), animroot, textkeys, ctrls, bone); + buildBones(skel, children[i].getPtr(), bone); } } } @@ -218,68 +70,14 @@ void NIFSkeletonLoader::loadResource(Ogre::Resource *resource) Nif::NIFFile::ptr nif(Nif::NIFFile::create(skel->getName())); const Nif::Node *node = static_cast(nif->getRoot(0)); - std::vector ctrls; - Ogre::Bone *animroot = NULL; - TextKeyMap textkeys; try { - buildBones(skel, node, animroot, textkeys, ctrls); + buildBones(skel, node); } catch(std::exception &e) { std::cerr<< "Exception while loading "<getName() < targets; - // TODO: If ctrls.size() == 0, check for a .kf file sharing the name of the .nif file - if(ctrls.size() == 0) // No animations? Then we're done. - return; - - float maxtime = 0.0f; - for(size_t i = 0;i < ctrls.size();i++) - { - const Nif::NiKeyframeController *ctrl = ctrls[i]; - maxtime = std::max(maxtime, ctrl->timeStop); - Nif::Named *target = dynamic_cast(ctrl->target.getPtr()); - if(target != NULL) - targets.push_back(target->name); - } - - if(targets.size() != ctrls.size()) - { - warn("Target size mismatch ("+Ogre::StringConverter::toString(targets.size())+" targets, "+ - Ogre::StringConverter::toString(ctrls.size())+" controllers)"); - return; - } - - std::string currentgroup; - TextKeyMap::const_iterator keyiter = textkeys.begin(); - for(keyiter = textkeys.begin();keyiter != textkeys.end();keyiter++) - { - std::string::size_type sep = keyiter->second.find(':'); - if((sep == currentgroup.length() && keyiter->second.compare(0, sep, currentgroup) == 0) || - (sep == sizeof("soundgen")-1 && keyiter->second.compare(0, sep, "soundgen") == 0) || - (sep == sizeof("sound")-1 && keyiter->second.compare(0, sep, "sound") == 0)) - continue; - currentgroup = keyiter->second.substr(0, sep); - - if(skel->hasAnimation(currentgroup)) - continue; - - TextKeyMap::const_iterator lastkeyiter = textkeys.end(); - while((--lastkeyiter)->first > keyiter->first) - { - if(lastkeyiter->second.find(':') == currentgroup.length() && - lastkeyiter->second.compare(0, currentgroup.length(), currentgroup) == 0) - break; - } - - buildAnimation(skel, currentgroup, ctrls, targets, keyiter->first, lastkeyiter->first); - } } diff --git a/components/nifogre/skeleton.hpp b/components/nifogre/skeleton.hpp index e71dcfb158..38cfe14e3d 100644 --- a/components/nifogre/skeleton.hpp +++ b/components/nifogre/skeleton.hpp @@ -36,8 +36,7 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader abort(); } - static void buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime); - void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *&animroot, TextKeyMap &textkeys, std::vector &ctrls, Ogre::Bone *parent=NULL); + void buildBones(Ogre::Skeleton *skel, const Nif::Node *node, Ogre::Bone *parent=NULL); // Lookup to retrieve an Ogre bone handle for a given Nif record index std::map mNifToOgreHandleMap; @@ -46,7 +45,6 @@ class NIFSkeletonLoader : public Ogre::ManualResourceLoader static LoaderMap sLoaders; public: - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk); void loadResource(Ogre::Resource *resource); static Ogre::SkeletonPtr createSkeleton(const std::string &name, const std::string &group, const Nif::Node *node); From 6f0b9a5f2cb98747715dbfa6c88b86f178c6f94c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 23 Apr 2013 21:42:59 -0700 Subject: [PATCH 0497/1537] Avoid unnecessary multimap copies --- components/nifogre/ogrenifloader.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index e451326fee..57aa794038 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -676,9 +676,8 @@ class NIFObjectLoader } - static TextKeyMap extractTextKeys(const Nif::NiTextKeyExtraData *tk) + static void extractTextKeys(const Nif::NiTextKeyExtraData *tk, TextKeyMap &textkeys) { - TextKeyMap textkeys; for(size_t i = 0;i < tk->list.size();i++) { const std::string &str = tk->list[i].text; @@ -698,7 +697,6 @@ class NIFObjectLoader pos = nextpos; } } - return textkeys; } @@ -730,7 +728,7 @@ class NIFObjectLoader const Nif::NiTextKeyExtraData *tk = static_cast(e.getPtr()); int trgtid = NIFSkeletonLoader::lookupOgreBoneHandle(name, node->recIndex); - objectlist.mTextKeys[trgtid] = extractTextKeys(tk); + extractTextKeys(tk, objectlist.mTextKeys[trgtid]); } else if(e->recType == Nif::RC_NiStringExtraData) { From 544011e0962b28b9cb978d90b9f1fe32455fb1ed Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:40:58 -0700 Subject: [PATCH 0498/1537] Fix 'start' text key fallback lookup --- apps/openmw/mwrender/animation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index cb54a03665..dc1312837a 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -412,7 +412,7 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); while(startkey != keys.end() && startkey->second != tag) startkey++; - if(startkey == keys.end() && tag == "loop start") + if(startkey == keys.end() && start == "loop start") { tag = groupname+": start"; startkey = keys.begin(); From 26cc86ffdcd152b9acb6b953fff7de7acf2c48a0 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 00:42:45 -0700 Subject: [PATCH 0499/1537] Use the Nif node's transform for skinned fixups --- components/nifogre/mesh.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index 5637cd8285..ca92f62d49 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -109,7 +109,6 @@ NIFMeshLoader::LoaderMap NIFMeshLoader::sLoaders; void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { - Ogre::SkeletonPtr skel; const Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector srcVerts = data->vertices; @@ -139,10 +138,6 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // explicitly attached later. mesh->setSkeletonName(mName); - // Get the skeleton resource, so vertices can be transformed into the bones' initial state. - Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); - skel = skelMgr->getByName(mName); - // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to // be a reliable way to do that. @@ -153,11 +148,10 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { - Ogre::Bone *bone = skel->getBone(bones[b]->name); Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); - mat = bone->_getFullTransform() * mat; + mat = bones[b]->getWorldTransform() * mat; const std::vector &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) @@ -310,6 +304,8 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Assign bone weights for this TriShape if(skin != NULL) { + Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); + const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) From 9e05ee53da793846d0ddebd0b960aba621a621a6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:18:08 -0700 Subject: [PATCH 0500/1537] Avoid looking for the controller if there is no NonAccum node Also, make sure there is a controller before updating the position. --- apps/openmw/mwrender/animation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index dc1312837a..a2b4298409 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -538,7 +538,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con const NifOgre::TextKeyMap &keys = objlist.mTextKeys.begin()->second; NifOgre::NodeTargetValue *nonaccumctrl = NULL; - if(layeridx == 0) + if(layeridx == 0 && mNonAccumRoot) { for(size_t i = 0;i < objlist.mControllers.size();i++) { @@ -601,14 +601,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) if(mLayer[layeridx].mNextKey->first > targetTime) { mLayer[layeridx].mTime = targetTime; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; - if(layeridx == 0 && mNonAccumRoot) + if(layeridx == 0 && mNonAccumCtrl) movement += updatePosition(); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); From 102b3bdef99d0d7ea1ee601565d3463a7cb5212d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 01:57:51 -0700 Subject: [PATCH 0501/1537] Update position by reference --- apps/openmw/mwrender/animation.cpp | 13 +++++++------ apps/openmw/mwrender/animation.hpp | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a2b4298409..a8b2a18979 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -392,18 +392,19 @@ void Animation::updateSkeletonInstance(const Ogre::SkeletonInstance *skelsrc, Og } -Ogre::Vector3 Animation::updatePosition() +void Animation::updatePosition(Ogre::Vector3 &position) { Ogre::Vector3 posdiff; - /* Get the non-accumulation root's difference from the last update. */ + /* Get the non-accumulation root's difference from the last update, and move the position + * accordingly. + */ posdiff = (mNonAccumCtrl->getTranslation(mLayer[0].mTime) - mLastPosition) * mAccumulate; + position += posdiff; /* Translate the accumulation root back to compensate for the move. */ mLastPosition += posdiff; mAccumRoot->setPosition(-mLastPosition); - - return posdiff; } bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) @@ -602,14 +603,14 @@ Ogre::Vector3 Animation::runAnimation(float duration) { mLayer[layeridx].mTime = targetTime; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); break; } NifOgre::TextKeyMap::const_iterator key(mLayer[layeridx].mNextKey++); mLayer[layeridx].mTime = key->first; if(layeridx == 0 && mNonAccumCtrl) - movement += updatePosition(); + updatePosition(movement); mLayer[layeridx].mPlaying = (key != mLayer[layeridx].mStopKey); timepassed = targetTime - mLayer[layeridx].mTime; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 4860f44f5c..a874cb1a8e 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -88,7 +88,7 @@ protected: /* Updates the position of the accum root node for the current time, and * returns the wanted movement vector from the previous update. */ - Ogre::Vector3 updatePosition(); + void updatePosition(Ogre::Vector3 &position); static NifOgre::TextKeyMap::const_iterator findGroupStart(const NifOgre::TextKeyMap &keys, const std::string &groupname); From 68a9a4de5f77153f16e41fea47654b722fa6119d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:12:27 -0700 Subject: [PATCH 0502/1537] Fix setting and getting KeyframeController transforms --- components/nifogre/ogrenifloader.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index 57aa794038..d36199f867 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -173,8 +173,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::FloatKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -193,8 +191,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::Vector3KeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -213,8 +209,6 @@ public: { if(time <= keys.front().mTime) return keys.front().mValue; - if(time >= keys.back().mTime) - return keys.back().mValue; Nif::QuaternionKeyList::VecType::const_iterator iter(keys.begin()+1); for(;iter != keys.end();iter++) @@ -241,21 +235,21 @@ public: { if(mRotations.mKeys.size() > 0) return interpKey(mRotations.mKeys, time); - return Ogre::Quaternion(); + return mNode->getOrientation(); } virtual Ogre::Vector3 getTranslation(float time) const { if(mTranslations.mKeys.size() > 0) return interpKey(mTranslations.mKeys, time); - return Ogre::Vector3(0.0f); + return mNode->getPosition(); } virtual Ogre::Vector3 getScale(float time) const { if(mScales.mKeys.size() > 0) return Ogre::Vector3(interpKey(mScales.mKeys, time)); - return Ogre::Vector3(1.0f); + return mNode->getScale(); } virtual Ogre::Real getValue() const @@ -266,9 +260,12 @@ public: virtual void setValue(Ogre::Real time) { - mNode->setOrientation(Value::getRotation(time)); - mNode->setPosition(Value::getTranslation(time)); - mNode->setScale(Value::getScale(time)); + if(mRotations.mKeys.size() > 0) + mNode->setOrientation(interpKey(mRotations.mKeys, time)); + if(mTranslations.mKeys.size() > 0) + mNode->setPosition(interpKey(mTranslations.mKeys, time)); + if(mScales.mKeys.size() > 0) + mNode->setScale(Ogre::Vector3(interpKey(mScales.mKeys, time))); } }; From 7241267d5c036f8c052598c18f04bdb8fef0b70e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:41:52 -0700 Subject: [PATCH 0503/1537] Make an AnimationValue for each animation layer --- apps/openmw/mwrender/animation.cpp | 8 +++--- apps/openmw/mwrender/animation.hpp | 40 ++++++++++++++++-------------- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index a8b2a18979..3d938cc258 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -58,8 +58,7 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL } Animation::Animation(const MWWorld::Ptr &ptr) - : mAnimationBaseValuePtr(OGRE_NEW AnimationValue(this, 0)) - , mPtr(ptr) + : mPtr(ptr) , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) @@ -71,6 +70,9 @@ Animation::Animation(const MWWorld::Ptr &ptr) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { + for(size_t i = 0;i < sMaxLayers;i++) + mAnimationValuePtr[i].bind(OGRE_NEW AnimationValue(this, i)); + /* As long as we remain under 128 active controllers, we can avoid * reallocations. */ mActiveCtrls.reserve(128); @@ -153,7 +155,7 @@ void Animation::addObjectList(Ogre::SceneNode *node, const std::string &model, b for(size_t i = 0;i < objlist.mControllers.size();i++) { if(objlist.mControllers[i].getSource().isNull()) - objlist.mControllers[i].setSource(mAnimationBaseValuePtr); + objlist.mControllers[i].setSource(mAnimationValuePtr[0]); } mActiveCtrls.insert(mActiveCtrls.end(), objlist.mControllers.begin(), objlist.mControllers.end()); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index a874cb1a8e..282cd3eca2 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -33,10 +33,6 @@ protected: virtual Ogre::Real getValue() const; virtual void setValue(Ogre::Real value); }; - Ogre::SharedPtr > mAnimationBaseValuePtr; - - MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; struct ObjectInfo { NifOgre::ObjectList mObjectList; @@ -47,20 +43,6 @@ protected: int mActiveLayers; }; - Ogre::SceneNode *mInsert; - Ogre::Entity *mSkelBase; - std::vector mObjects; - Ogre::Node *mAccumRoot; - Ogre::Bone *mNonAccumRoot; - Ogre::Vector3 mAccumulate; - Ogre::Vector3 mLastPosition; - - NifOgre::NodeTargetValue *mNonAccumCtrl; - float mAnimVelocity; - float mAnimSpeedMult; - std::vector > mActiveCtrls; - - static const size_t sMaxLayers = 1; struct AnimLayer { std::string mGroupName; std::vector > *mControllers; @@ -76,7 +58,27 @@ protected: bool mLooping; AnimLayer(); - } mLayer[sMaxLayers]; + }; + + MWWorld::Ptr mPtr; + MWMechanics::CharacterController *mController; + + Ogre::SceneNode *mInsert; + Ogre::Entity *mSkelBase; + std::vector mObjects; + Ogre::Node *mAccumRoot; + Ogre::Bone *mNonAccumRoot; + Ogre::Vector3 mAccumulate; + Ogre::Vector3 mLastPosition; + + NifOgre::NodeTargetValue *mNonAccumCtrl; + float mAnimVelocity; + float mAnimSpeedMult; + std::vector > mActiveCtrls; + + static const size_t sMaxLayers = 1; + AnimLayer mLayer[sMaxLayers]; + Ogre::SharedPtr > mAnimationValuePtr[sMaxLayers]; static float calcAnimVelocity(const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, From c58dfbe921cda569f950648f3307145a9c2cfe37 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 04:56:39 -0700 Subject: [PATCH 0504/1537] Specify the loop count to Animation::play --- apps/openmw/mwmechanics/character.cpp | 12 ++++++------ apps/openmw/mwrender/animation.cpp | 19 ++++++++++++------- apps/openmw/mwrender/animation.hpp | 6 +++--- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 07f7b69401..664ed7c032 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -123,7 +123,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } CharacterController::CharacterController(const CharacterController &rhs) @@ -155,7 +155,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } return; } @@ -164,7 +164,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) { mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", false); + mAnimation->play(mCurrentGroup, "loop start", "stop", 0); } else if(mAnimQueue.size() > 0) { @@ -172,7 +172,7 @@ void CharacterController::markerEvent(float time, const std::string &evt) if(mAnimQueue.size() > 0) { mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", false); + mAnimation->play(mCurrentGroup, "start", "stop", 0); } } return; @@ -284,7 +284,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.push_back(groupname); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", false); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); } else if(mode == 0) { @@ -316,7 +316,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop); + mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3d938cc258..4e82f0b8c3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -23,7 +23,7 @@ Animation::AnimLayer::AnimLayer() , mTextKeys(NULL) , mTime(0.0f) , mPlaying(false) - , mLooping(false) + , mLoopCount(0) { } @@ -449,14 +449,20 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: return true; } -void Animation::doLoop(size_t layeridx) +bool Animation::doLoop(size_t layeridx) { + if(mLayer[layeridx].mLoopCount == 0) + return false; + mLayer[layeridx].mLoopCount--; + mLayer[layeridx].mTime = mLayer[layeridx].mLoopStartKey->first; mLayer[layeridx].mNextKey = mLayer[layeridx].mLoopStartKey; mLayer[layeridx].mNextKey++; mLayer[layeridx].mPlaying = true; if(layeridx == 0 && mNonAccumCtrl) mLastPosition = mNonAccumCtrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; + + return true; } @@ -495,9 +501,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { - if(mLayer[layeridx].mLooping) + if(doLoop(layeridx)) { - doLoop(layeridx); if(mLayer[layeridx].mTime >= time) return false; return true; @@ -510,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -527,7 +532,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName.clear(); mLayer[layeridx].mTextKeys = NULL; mLayer[layeridx].mControllers = NULL; - mLayer[layeridx].mLooping = false; + mLayer[layeridx].mLoopCount = 0; mLayer[layeridx].mPlaying = false; foundanim = true; @@ -562,7 +567,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; mLayer[layeridx].mControllers = &objlist.mControllers; - mLayer[layeridx].mLooping = loop; + mLayer[layeridx].mLoopCount = loops; mLayer[layeridx].mPlaying = true; if(layeridx == 0) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 282cd3eca2..1b300887fc 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -55,7 +55,7 @@ protected: float mTime; bool mPlaying; - bool mLooping; + size_t mLoopCount; AnimLayer(); }; @@ -101,7 +101,7 @@ protected: */ bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); - void doLoop(size_t layeridx); + bool doLoop(size_t layeridx); bool handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_iterator &key); @@ -129,7 +129,7 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, bool loop); + void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); Ogre::Node *getNode(const std::string &name); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 41770d4891..c22d8a4da4 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", false); + mAnimation->play("inventoryhandtohand", "start", "stop", 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", false); + mAnimation->play("idle", "start", "stop", 0); updateCamera(); } From b482d5be097b16a8df8ecc04c8b25252e81e746c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 05:23:45 -0700 Subject: [PATCH 0505/1537] Add a method to check if a given layer is playing --- apps/openmw/mwrender/animation.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 1b300887fc..87c57ebf7b 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -132,6 +132,9 @@ public: void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); virtual Ogre::Vector3 runAnimation(float timepassed); + bool isPlaying(size_t layeridx) const + { return mLayer[layeridx].mPlaying; } + Ogre::Node *getNode(const std::string &name); }; From e8cabc94349d95bbb9e23a3604e8d1afe85ed8b1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:32:11 -0700 Subject: [PATCH 0506/1537] Pass the loop count from loopgroup to the play method Instead of queueing each iteration separately. --- apps/openmw/mwmechanics/character.cpp | 34 +++++++-------------------- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 11 ++++++++- 3 files changed, 20 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 664ed7c032..086a2fc252 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -150,29 +150,16 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) void CharacterController::markerEvent(float time, const std::string &evt) { - if(evt == "loop stop") - { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - return; - } if(evt == "stop") { - if(mAnimQueue.size() >= 2 && mAnimQueue[0] == mAnimQueue[1]) - { - mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "loop start", "stop", 0); - } - else if(mAnimQueue.size() > 0) + if(mAnimQueue.size() > 0) { mAnimQueue.pop_front(); if(mAnimQueue.size() > 0) { - mCurrentGroup = mAnimQueue.front(); - mAnimation->play(mCurrentGroup, "start", "stop", 0); + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimation->play(mCurrentGroup, "start", "stop", count); } } return; @@ -223,7 +210,6 @@ void CharacterController::update(float duration, Movement &movement) if(vec.x > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunRight : CharState_SwimWalkRight) : (sneak ? CharState_SneakRight : (isrunning ? CharState_RunRight : CharState_WalkRight)), true); - else if(vec.x < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunLeft : CharState_SwimWalkLeft) : (sneak ? CharState_SneakLeft : (isrunning ? CharState_RunLeft : CharState_WalkLeft)), true); @@ -236,10 +222,10 @@ void CharacterController::update(float duration, Movement &movement) if(vec.y > 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunForward : CharState_SwimWalkForward) : (sneak ? CharState_SneakForward : (isrunning ? CharState_RunForward : CharState_WalkForward)), true); - else if(vec.y < 0.0f) setState(inwater ? (isrunning ? CharState_SwimRunBack : CharState_SwimWalkBack) : (sneak ? CharState_SneakBack : (isrunning ? CharState_RunBack : CharState_WalkBack)), true); + // Apply any sideways movement manually movement.mPosition[0] += vec.x * (speed*duration); } @@ -250,7 +236,7 @@ void CharacterController::update(float duration, Movement &movement) else if(rot.z < 0.0f) setState(CharState_TurnLeft, true); } - else if(mAnimQueue.size() == 0) + else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); movement.mRotation[0] += rot.x * duration; @@ -280,17 +266,15 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int if(mode != 0 || mAnimQueue.size() == 0) { mAnimQueue.clear(); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { mAnimQueue.resize(1); - while(count-- > 0) - mAnimQueue.push_back(groupname); + mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 5b5a65f797..4453b078db 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -72,7 +72,7 @@ class CharacterController MWWorld::Ptr mPtr; MWRender::Animation *mAnimation; - typedef std::deque AnimationQueue; + typedef std::deque > AnimationQueue; AnimationQueue mAnimQueue; std::string mCurrentGroup; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 4e82f0b8c3..b205d95192 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,16 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) + if(evt.compare(off, len, "loop stop") == 0) + { + if(doLoop(layeridx)) + { + if(mLayer[layeridx].mTime >= time) + return false; + } + return true; + } + if(evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { From b80891099e0171af7a58dd9733b4abfd901fc3aa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 06:48:34 -0700 Subject: [PATCH 0507/1537] Don't use the character controller to handle text keys The Animation class has the Ptr and can call to whatever subsystem is needed. --- apps/openmw/mwmechanics/character.cpp | 38 +++++++++------------------ apps/openmw/mwmechanics/character.hpp | 6 ----- apps/openmw/mwrender/animation.cpp | 16 +++-------- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 086a2fc252..bbf679cdae 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -148,27 +148,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) } -void CharacterController::markerEvent(float time, const std::string &evt) -{ - if(evt == "stop") - { - if(mAnimQueue.size() > 0) - { - mAnimQueue.pop_front(); - if(mAnimQueue.size() > 0) - { - mCurrentGroup = mAnimQueue.front().first; - size_t count = mAnimQueue.front().second; - mAnimation->play(mCurrentGroup, "start", "stop", count); - } - } - return; - } - - std::cerr<< "Unhandled animation event: "<isPlaying(0)) - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + { + if(mAnimQueue.size() > 0) + { + mCurrentGroup = mAnimQueue.front().first; + size_t count = mAnimQueue.front().second; + mAnimQueue.pop_front(); + mAnimation->play(mCurrentGroup, "start", "stop", count); + } + else + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + } movement.mRotation[0] += rot.x * duration; movement.mRotation[1] += rot.y * duration; @@ -263,17 +252,16 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int else { count = std::max(count, 1); - if(mode != 0 || mAnimQueue.size() == 0) + if(mode != 0 || getState() != CharState_SpecialIdle) { mAnimQueue.clear(); - mAnimQueue.push_back(std::make_pair(groupname, count-1)); mCurrentGroup = groupname; mState = CharState_SpecialIdle; mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); } else if(mode == 0) { - mAnimQueue.resize(1); + mAnimQueue.clear(); mAnimQueue.push_back(std::make_pair(groupname, count-1)); } } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4453b078db..4bbea15519 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,12 +79,6 @@ class CharacterController CharacterState mState; bool mSkipAnim; -protected: - /* Called by the animation whenever a new text key is reached. */ - void markerEvent(float time, const std::string &evt); - - friend class MWRender::Animation; - public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); CharacterController(const CharacterController &rhs); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b205d95192..c0fee0d3b6 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -499,7 +499,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ return true; } - if(evt.compare(off, len, "loop stop") == 0) + if(evt.compare(off, len, "loop stop") == 0 || evt.compare(off, len, "stop") == 0) { if(doLoop(layeridx)) { @@ -508,18 +508,8 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } return true; } - if(evt.compare(off, len, "stop") == 0) - { - if(doLoop(layeridx)) - { - if(mLayer[layeridx].mTime >= time) - return false; - return true; - } - // fall-through - } - if(mController) - mController->markerEvent(time, evt.substr(off)); + + std::cerr<< "Unhandled animation textkey: "< Date: Wed, 24 Apr 2013 07:10:41 -0700 Subject: [PATCH 0508/1537] Remove the character controller from the Animation class --- apps/openmw/mwmechanics/character.cpp | 13 ------------- apps/openmw/mwmechanics/character.hpp | 1 - apps/openmw/mwrender/animation.cpp | 9 +-------- apps/openmw/mwrender/animation.hpp | 12 +++--------- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index bbf679cdae..2a7ab8b09b 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -108,8 +108,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim if(!mAnimation) return; - mAnimation->setController(this); - getStateInfo(mState, &mCurrentGroup); if(MWWorld::Class::get(mPtr).isActor()) { @@ -126,17 +124,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); } -CharacterController::CharacterController(const CharacterController &rhs) - : mPtr(rhs.mPtr), mAnimation(rhs.mAnimation), mAnimQueue(rhs.mAnimQueue) - , mCurrentGroup(rhs.mCurrentGroup), mState(rhs.mState) - , mSkipAnim(rhs.mSkipAnim) -{ - if(!mAnimation) - return; - /* We've been copied. Update the animation with the new controller. */ - mAnimation->setController(this); -} - CharacterController::~CharacterController() { } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4bbea15519..ffd220ff2f 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -81,7 +81,6 @@ class CharacterController public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop); - CharacterController(const CharacterController &rhs); virtual ~CharacterController(); void updatePtr(const MWWorld::Ptr &ptr); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c0fee0d3b6..c2f4535164 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -59,14 +59,13 @@ void Animation::destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectL Animation::Animation(const MWWorld::Ptr &ptr) : mPtr(ptr) - , mController(NULL) , mInsert(NULL) , mSkelBase(NULL) , mAccumRoot(NULL) , mNonAccumRoot(NULL) + , mNonAccumCtrl(NULL) , mAccumulate(0.0f) , mLastPosition(0.0f) - , mNonAccumCtrl(NULL) , mAnimVelocity(0.0f) , mAnimSpeedMult(1.0f) { @@ -299,12 +298,6 @@ bool Animation::hasAnimation(const std::string &anim) } -void Animation::setController(MWMechanics::CharacterController *controller) -{ - mController = controller; -} - - void Animation::setAccumulation(const Ogre::Vector3 &accum) { mAccumulate = accum; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 87c57ebf7b..526bca69a8 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -8,10 +8,6 @@ #include "../mwworld/ptr.hpp" -namespace MWMechanics -{ - class CharacterController; -} namespace MWRender { @@ -61,20 +57,20 @@ protected: }; MWWorld::Ptr mPtr; - MWMechanics::CharacterController *mController; Ogre::SceneNode *mInsert; Ogre::Entity *mSkelBase; std::vector mObjects; Ogre::Node *mAccumRoot; Ogre::Bone *mNonAccumRoot; + NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate; Ogre::Vector3 mLastPosition; - NifOgre::NodeTargetValue *mNonAccumCtrl; + std::vector > mActiveCtrls; + float mAnimVelocity; float mAnimSpeedMult; - std::vector > mActiveCtrls; static const size_t sMaxLayers = 1; AnimLayer mLayer[sMaxLayers]; @@ -116,8 +112,6 @@ public: Animation(const MWWorld::Ptr &ptr); virtual ~Animation(); - void setController(MWMechanics::CharacterController *controller); - void updatePtr(const MWWorld::Ptr &ptr); bool hasAnimation(const std::string &anim); From 53fb17da10436022178562d5d573659f769e0102 Mon Sep 17 00:00:00 2001 From: Glorf Date: Wed, 24 Apr 2013 21:42:04 +0200 Subject: [PATCH 0509/1537] Rotation system fixes --- apps/openmw/mwscript/transformationextensions.cpp | 9 +++------ apps/openmw/mwworld/worldimp.cpp | 8 ++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index beb6c3d8c1..f2179897dc 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -153,15 +153,15 @@ namespace MWScript if (axis=="x") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[0]); } else if (axis=="y") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[1]); } else if (axis=="z") { - runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); + runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+ptr.getRefData().getLocalRotation().rot[2]); } else throw std::runtime_error ("invalid ration axis: " + axis); @@ -563,17 +563,14 @@ namespace MWScript if (axis == "x") { - ptr.getRefData().getLocalRotation().rot[0]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_X); } else if (axis == "y") { - ptr.getRefData().getLocalRotation().rot[1]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Y); } else if (axis == "z") { - ptr.getRefData().getLocalRotation().rot[2]+=rotation; MWBase::Environment::get().getWorld()->localRotateObject(ptr, rotation, Ogre::Vector3::UNIT_Z); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 69bcad619d..aa9107c6ec 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -827,6 +827,14 @@ namespace MWWorld void World::localRotateObject (const Ptr& ptr, float rotation, Ogre::Vector3 axis) { if (ptr.getRefData().getBaseNode() != 0) { + + if(axis==Ogre::Vector3::UNIT_X) + ptr.getRefData().getLocalRotation().rot[0]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Y) + ptr.getRefData().getLocalRotation().rot[1]+=rotation; + else if(axis==Ogre::Vector3::UNIT_Z) + ptr.getRefData().getLocalRotation().rot[2]+=rotation; + ptr.getRefData().getBaseNode()->rotate(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-rotation).valueRadians()), axis)); mPhysics->rotateObject(ptr); } From c0102954f1d435b21aa2e6a7f1b6d61207ac925b Mon Sep 17 00:00:00 2001 From: Emanuel Guevel Date: Sat, 30 Mar 2013 13:28:17 +0100 Subject: [PATCH 0510/1537] Add non-breaking space to font code range --- files/mygui/openmw_font.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/files/mygui/openmw_font.xml b/files/mygui/openmw_font.xml index b1446fae14..f1be51e165 100644 --- a/files/mygui/openmw_font.xml +++ b/files/mygui/openmw_font.xml @@ -9,6 +9,7 @@ + From cd57e3f896260e480db9fab1aa0d0b9e03f2aa09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 18 Apr 2013 23:51:43 +0200 Subject: [PATCH 0511/1537] Auto calculate attributes if there are not specified in the NPC record --- apps/openmw/mwclass/npc.cpp | 66 +++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 7cda87bb15..ea49ae4a4c 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -49,6 +49,67 @@ namespace { return new CustomData (*this); } + + void autoCalculateAttributes (const ESM::NPC* npc, MWMechanics::CreatureStats& creatureStats) + { + // race bonus + const ESM::Race *race = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mRace); + + bool male = (npc->mFlags & ESM::NPC::Female) == 0; + + int level = creatureStats.getLevel(); + + for (int i=0; imData.mAttributeValues[i]; + creatureStats.getAttribute(i).setBase (male ? attribute.mMale : attribute.mFemale); + } + + // class bonus + const ESM::Class *class_ = + MWBase::Environment::get().getWorld()->getStore().get().find(npc->mClass); + + for (int i=0; i<2; ++i) + { + int attribute = class_->mData.mAttribute[i]; + if (attribute>=0 && attribute<8) + { + creatureStats.getAttribute(attribute).setBase ( + creatureStats.getAttribute(attribute).getBase() + 10); + } + } + + // skill bonus + for (int attribute=0; attributegetStore().get().find(j); + + if (skill->mData.mAttribute != attribute) + continue; + + // is this a minor or major skill? + float add=0.2; + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][0] == j) + add=0.5; + } + for (int k=0; k<5; ++k) + { + if (class_->mData.mSkills[k][1] == j) + add=1.0; + } + modifierSum += add; + } + creatureStats.getAttribute(attribute).setBase ( std::min(creatureStats.getAttribute(attribute).getBase() + + static_cast((level-1) * modifierSum+0.5), 100) ); + } + } } namespace MWClass @@ -126,15 +187,14 @@ namespace MWClass } else { - for (int i=0; i<8; ++i) - data->mCreatureStats.getAttribute (i).set (10); - for (int i=0; i<3; ++i) data->mCreatureStats.setDynamic (i, 10); data->mCreatureStats.setLevel(ref->mBase->mNpdt12.mLevel); data->mNpcStats.setBaseDisposition(ref->mBase->mNpdt12.mDisposition); data->mNpcStats.setReputation(ref->mBase->mNpdt12.mReputation); + + autoCalculateAttributes(ref->mBase, data->mCreatureStats); } data->mCreatureStats.setAiSetting (0, ref->mBase->mAiData.mHello); From 2c8b0a154175f3320fe4e082a5208d538f707875 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 00:26:36 +0200 Subject: [PATCH 0512/1537] last minute change to changelog --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index 5f38457765..d5a5dcc183 100644 --- a/readme.txt +++ b/readme.txt @@ -136,6 +136,7 @@ Bug #700: "On the rocks" mod does not load its UV coordinates correctly. Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon +Bug #725: Auto calculate stats Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From 21bdcc9f20d14e7d5aabf906860cee573e0e31a4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 01:33:04 +0200 Subject: [PATCH 0513/1537] Only use the shader based mygui manager if the fixed pipeline is unavailable --- libs/openengine/gui/manager.cpp | 30 ++++++++++++++++++++++++++---- libs/openengine/gui/manager.hpp | 5 +++-- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/libs/openengine/gui/manager.cpp b/libs/openengine/gui/manager.cpp index f9117586fe..a0a4ab0aea 100644 --- a/libs/openengine/gui/manager.cpp +++ b/libs/openengine/gui/manager.cpp @@ -559,6 +559,8 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool assert(mgr); mSceneMgr = mgr; + mShaderRenderManager = NULL; + mRenderManager = NULL; using namespace MyGUI; @@ -574,7 +576,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool // Set up OGRE platform (bypassing OgrePlatform). We might make this more generic later. mLogManager = new LogManager(); - mRenderManager = new MyGUI::ShaderBasedRenderManager(); + if (!Ogre::Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(Ogre::RSC_FIXED_FUNCTION)) + mShaderRenderManager = new MyGUI::ShaderBasedRenderManager(); + else + mRenderManager = new MyGUI::OgreRenderManager(); mDataManager = new MyGUI::FixedOgreDataManager(); LogManager::getInstance().setSTDOutputEnabled(logging); @@ -582,7 +587,10 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool if (!theLogFile.empty()) LogManager::getInstance().createDefaultSource(theLogFile); - mRenderManager->initialise(wnd, mgr); + if (mShaderRenderManager) + mShaderRenderManager->initialise(wnd, mgr); + else + mRenderManager->initialise(wnd, mgr); mDataManager->initialise("General"); // Create GUI @@ -592,8 +600,16 @@ void MyGUIManager::setup(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool void MyGUIManager::updateWindow (Ogre::RenderWindow *wnd) { - mRenderManager->setRenderWindow (wnd); - mRenderManager->setActiveViewport(0); + if (mShaderRenderManager) + { + mShaderRenderManager->setRenderWindow (wnd); + mShaderRenderManager->setActiveViewport(0); + } + else + { + mRenderManager->setRenderWindow (wnd); + mRenderManager->setActiveViewport(0); + } } void MyGUIManager::shutdown() @@ -606,6 +622,12 @@ void MyGUIManager::shutdown() delete mRenderManager; mRenderManager = NULL; } + if(mShaderRenderManager) + { + mShaderRenderManager->shutdown(); + delete mShaderRenderManager; + mShaderRenderManager = NULL; + } if(mDataManager) { mDataManager->shutdown(); diff --git a/libs/openengine/gui/manager.hpp b/libs/openengine/gui/manager.hpp index eec867ff8b..9535f2a24e 100644 --- a/libs/openengine/gui/manager.hpp +++ b/libs/openengine/gui/manager.hpp @@ -8,6 +8,7 @@ namespace MyGUI class Gui; class LogManager; class OgreDataManager; + class OgreRenderManager; class ShaderBasedRenderManager; } @@ -25,12 +26,12 @@ namespace GUI MyGUI::Gui *mGui; MyGUI::LogManager* mLogManager; MyGUI::OgreDataManager* mDataManager; - MyGUI::ShaderBasedRenderManager* mRenderManager; + MyGUI::OgreRenderManager* mRenderManager; + MyGUI::ShaderBasedRenderManager* mShaderRenderManager; Ogre::SceneManager* mSceneMgr; public: - MyGUIManager() : mLogManager(NULL), mDataManager(NULL), mRenderManager(NULL), mGui(NULL) {} MyGUIManager(Ogre::RenderWindow *wnd, Ogre::SceneManager *mgr, bool logging=false, const std::string& logDir = std::string("")) { setup(wnd,mgr,logging, logDir); From 87ce2110dcc912394a6d49599a7bb7558bac68a0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 19 Apr 2013 14:41:26 +0200 Subject: [PATCH 0514/1537] hotfix for CharacterPreview destructor --- apps/openmw/mwrender/characterpreview.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 8396acaea8..41770d4891 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -21,13 +21,15 @@ namespace MWRender CharacterPreview::CharacterPreview(MWWorld::Ptr character, int sizeX, int sizeY, const std::string& name, Ogre::Vector3 position, Ogre::Vector3 lookAt) - : mSizeX(sizeX) - , mSizeY(sizeY) - , mName(name) + + : mSceneMgr (0) , mPosition(position) , mLookAt(lookAt) , mCharacter(character) , mAnimation(NULL) + , mName(name) + , mSizeX(sizeX) + , mSizeY(sizeY) { } @@ -88,16 +90,20 @@ namespace MWRender CharacterPreview::~CharacterPreview () { - //Ogre::TextureManager::getSingleton().remove(mName); - mSceneMgr->destroyCamera (mName); - delete mAnimation; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneMgr) + { + //Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyAllCameras(); + delete mAnimation; + Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + } } void CharacterPreview::rebuild() { assert(mAnimation); delete mAnimation; + mAnimation = 0; mAnimation = new NpcAnimation(mCharacter, mNode, MWWorld::Class::get(mCharacter).getInventoryStore(mCharacter), 0, (renderHeadOnly() ? NpcAnimation::VM_HeadOnly : NpcAnimation::VM_Normal)); From 51580ead4f9c20f8b683384c618c5f1b25c2afd7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Fri, 19 Apr 2013 17:57:22 +0200 Subject: [PATCH 0515/1537] Fix consecutive dialogue choices --- apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 9380ab76cd..220adf566a 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -426,6 +426,7 @@ namespace MWDialogue void DialogueManager::questionAnswered (const std::string& answer) { + if (mChoiceMap.find(answer) != mChoiceMap.end()) { mChoice = mChoiceMap[answer]; @@ -442,6 +443,10 @@ namespace MWDialogue std::string text = info->mResponse; parseText (text); + mChoiceMap.clear(); + mChoice = -1; + mIsInChoice = false; + MWScript::InterpreterContext interpreterContext(&mActor.getRefData().getLocals(),mActor); MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addText (Interpreter::fixDefinesDialog(text, interpreterContext)); MWBase::Environment::get().getJournal()->addTopic (mLastTopic, info->mId); @@ -449,9 +454,6 @@ namespace MWDialogue mLastDialogue = *info; } } - mChoiceMap.clear(); - mChoice = -1; - mIsInChoice = false; } updateTopics(); From 2dc01fe56b923c382ebfe7da5c1829d8580bb450 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 21 Apr 2013 11:41:09 -0700 Subject: [PATCH 0516/1537] fixed the type of iterator uses in MWWorld::Store The containers type used to declare some iterators was not an exact match for the type of the container the iterator was being initialized from. This was causing build failure on windows. --- apps/openmw/mwworld/store.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 959b944e10..7949cbe002 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -475,7 +475,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -493,7 +493,7 @@ namespace MWWorld cell.mData.mX = x, cell.mData.mY = y; std::pair key(x, y); - std::map, ESM::Cell>::const_iterator it = mExt.find(key); + DynamicExt::const_iterator it = mExt.find(key); if (it != mExt.end()) { return &(it->second); } @@ -534,7 +534,7 @@ namespace MWWorld void setUp() { //typedef std::vector::iterator Iterator; - typedef std::map, ESM::Cell>::iterator ExtIterator; + typedef DynamicExt::iterator ExtIterator; typedef std::map::iterator IntIterator; //std::sort(mInt.begin(), mInt.end(), RecordCmp()); From a7092ef2d709a575848451ade18e45e360f80f09 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 21 Apr 2013 21:24:48 +0200 Subject: [PATCH 0517/1537] Fix activation not working sometimes The current player cell was only being updated when the reference was not empty, causing it to incorrectly detect a cell change the first time something was activated in a newly visited cell, immediately closing the opened dialogue again. --- apps/openmw/mwgui/referenceinterface.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwgui/referenceinterface.cpp b/apps/openmw/mwgui/referenceinterface.cpp index 66e036d929..86a85be18e 100644 --- a/apps/openmw/mwgui/referenceinterface.cpp +++ b/apps/openmw/mwgui/referenceinterface.cpp @@ -18,17 +18,17 @@ namespace MWGui 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) + || (!mPtr.isEmpty() && mPtr.getRefData().getCount() == 0)) { - mPtr = MWWorld::Ptr(); - onReferenceUnavailable(); + if (!mPtr.isEmpty()) + { + mPtr = MWWorld::Ptr(); + onReferenceUnavailable(); + } } mCurrentPlayerCell = playerCell; From baa7a9160c35b4ce13dde8666a2039eb998354e1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 22 Apr 2013 07:57:53 +0200 Subject: [PATCH 0518/1537] Rank condition should always fail if NPC is not in a faction --- apps/openmw/mwdialogue/filter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwdialogue/filter.cpp b/apps/openmw/mwdialogue/filter.cpp index 78969ffd0b..52c7bd4f34 100644 --- a/apps/openmw/mwdialogue/filter.cpp +++ b/apps/openmw/mwdialogue/filter.cpp @@ -73,6 +73,11 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const if (iter->second < info.mData.mRank) return false; } + else if (info.mData.mRank != -1) + { + // if there is a rank condition, but the NPC is not in a faction, always fail + return false; + } // Gender if (!isCreature) From 8d0e5fc0c4b7272508309e4325ab6c5590b2aa8b Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 22 Apr 2013 09:56:11 +0200 Subject: [PATCH 0519/1537] updated changelog once more --- readme.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.txt b/readme.txt index d5a5dcc183..c033f95475 100644 --- a/readme.txt +++ b/readme.txt @@ -137,6 +137,8 @@ Bug #702: Some race mods don't work Bug #711: Crash during character creation Bug #715: Growing Tauryon Bug #725: Auto calculate stats +Bug #728: Failure to open container and talk dialogue +Bug #731: Crash with Mush-Mere's "background" topic Feature #55/657: Item Repairing Feature #62/87: Enchanting Feature #99: Pathfinding From ad05f238deaec2679336e7d0c35366b53cdfa4c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 23 Apr 2013 22:47:21 +0200 Subject: [PATCH 0520/1537] Use one vertex buffer for all UV coordinates --- components/nifogre/mesh.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/components/nifogre/mesh.cpp b/components/nifogre/mesh.cpp index c0a7af5c30..6d940deed3 100644 --- a/components/nifogre/mesh.cpp +++ b/components/nifogre/mesh.cpp @@ -260,13 +260,24 @@ void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape // Texture UV coordinates size_t numUVs = data->uvlist.size(); - for(size_t i = 0;i < numUVs;i++) + if (numUVs) { - vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2), - srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); - vbuf->writeData(0, vbuf->getSizeInBytes(), &data->uvlist[i][0], true); + size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); + + for(size_t i = 0; i < numUVs; i++) + decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); + + vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), + Ogre::HardwareBuffer::HBU_STATIC); + + std::vector allUVs; + allUVs.reserve(srcVerts.size()*numUVs); + for (size_t vert = 0; vertuvlist[i][vert]); + + vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); - decl->addElement(nextBuf, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); bind->setBinding(nextBuf++, vbuf); } From 933f89414842eaa566803bb6ed506e85380fd2e4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 02:31:51 +0200 Subject: [PATCH 0521/1537] Added Blind and Night Eye effects --- apps/openmw/mwrender/renderingmanager.cpp | 27 ++++++++++++++++------- libs/openengine/ogre/fader.cpp | 12 +++++----- libs/openengine/ogre/fader.hpp | 4 ++++ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 029cf394b4..da51f10c1c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -30,6 +30,8 @@ #include "../mwbase/inputmanager.hpp" // FIXME #include "../mwbase/windowmanager.hpp" // FIXME +#include "../mwmechanics/creaturestats.hpp" + #include "../mwworld/ptr.hpp" #include "../mwworld/player.hpp" @@ -315,13 +317,15 @@ void RenderingManager::update (float duration, bool paused) { MWBase::World *world = MWBase::Environment::get().getWorld(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + int blind = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::Blind)).mMagnitude; + mRendering.getFader()->setFactor(1.f-(blind / 100.f)); + + setAmbientMode(); + // player position - MWWorld::RefData &data = - MWBase::Environment::get() - .getWorld() - ->getPlayer() - .getPlayer() - .getRefData(); + MWWorld::RefData &data = player.getRefData(); float *_playerPos = data.getPosition().pos; Ogre::Vector3 playerPos(_playerPos[0], _playerPos[1], _playerPos[2]); @@ -597,8 +601,15 @@ void RenderingManager::setSunColour(const Ogre::ColourValue& colour) void RenderingManager::setAmbientColour(const Ogre::ColourValue& colour) { - mRendering.getScene()->setAmbientLight(colour); - mTerrainManager->setAmbient(colour); + mAmbientColor = colour; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int nightEye = MWWorld::Class::get(player).getCreatureStats(player).getMagicEffects().get(MWMechanics::EffectKey(ESM::MagicEffect::NightEye)).mMagnitude; + Ogre::ColourValue final = colour; + final += Ogre::ColourValue(0.7,0.7,0.7,0) * std::min(1.f, (nightEye/100.f)); + + mRendering.getScene()->setAmbientLight(final); + mTerrainManager->setAmbient(final); } void RenderingManager::sunEnable(bool real) diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp index 9390d06647..923b0b7e38 100644 --- a/libs/openengine/ogre/fader.cpp +++ b/libs/openengine/ogre/fader.cpp @@ -19,6 +19,7 @@ Fader::Fader(Ogre::SceneManager* sceneMgr) , mTargetAlpha(0.f) , mCurrentAlpha(0.f) , mStartAlpha(0.f) + , mFactor(1.f) { // Create the fading material MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); @@ -62,19 +63,20 @@ void Fader::update(float dt) mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha); if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha; } - - applyAlpha(); - + mRemainingTime -= dt; } - if (mCurrentAlpha == 0.f) mRectangle->setVisible(false); + if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f) + mRectangle->setVisible(false); + else + applyAlpha(); } void Fader::applyAlpha() { mRectangle->setVisible(true); - mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, mCurrentAlpha); + mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 1.f-((1.f-mCurrentAlpha) * mFactor)); } void Fader::fadeIn(float time) diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp index bddf5dc919..53124e2f65 100644 --- a/libs/openengine/ogre/fader.hpp +++ b/libs/openengine/ogre/fader.hpp @@ -29,6 +29,8 @@ namespace Render void fadeOut(const float time); void fadeTo(const int percent, const float time); + void setFactor (float factor) { mFactor = factor; } + private: enum FadingMode { @@ -49,6 +51,8 @@ namespace Render float mCurrentAlpha; float mStartAlpha; + float mFactor; + Ogre::SceneManager* mSceneMgr; }; }} From 0817d59f23d4b2f36711109696c87cf6c22ad672 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 24 Apr 2013 19:09:36 -0700 Subject: [PATCH 0522/1537] Allow specifying where to start in an animation --- apps/openmw/mwmechanics/character.cpp | 14 +++++++------- apps/openmw/mwrender/animation.cpp | 18 +++++++++++++----- apps/openmw/mwrender/animation.hpp | 18 ++++++++++++++++-- apps/openmw/mwrender/characterpreview.cpp | 4 ++-- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 2a7ab8b09b..9397b2e356 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -121,7 +121,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim mAnimation->setAccumulation(Ogre::Vector3(0.0f)); } if(mAnimation->hasAnimation(mCurrentGroup)) - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 1.0f, loop ? (~(size_t)0) : 0); } CharacterController::~CharacterController() @@ -204,15 +204,15 @@ void CharacterController::update(float duration, Movement &movement) } else if(getState() != CharState_SpecialIdle || !mAnimation->isPlaying(0)) { - if(mAnimQueue.size() > 0) + if(mAnimQueue.size() == 0) + setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); + else { mCurrentGroup = mAnimQueue.front().first; size_t count = mAnimQueue.front().second; mAnimQueue.pop_front(); - mAnimation->play(mCurrentGroup, "start", "stop", count); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, count); } - else - setState((inwater ? CharState_IdleSwim : (sneak ? CharState_IdleSneak : CharState_Idle)), true); } movement.mRotation[0] += rot.x * duration; @@ -244,7 +244,7 @@ void CharacterController::playGroup(const std::string &groupname, int mode, int mAnimQueue.clear(); mCurrentGroup = groupname; mState = CharState_SpecialIdle; - mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", count-1); + mAnimation->play(mCurrentGroup, ((mode==2) ? "loop start" : "start"), "stop", 0.0f, count-1); } else if(mode == 0) { @@ -275,7 +275,7 @@ void CharacterController::setState(CharacterState state, bool loop) if(mAnimation->hasAnimation(anim)) { mCurrentGroup = anim; - mAnimation->play(mCurrentGroup, "start", "stop", loop ? (~(size_t)0) : 0); + mAnimation->play(mCurrentGroup, "start", "stop", 0.0f, loop ? (~(size_t)0) : 0); } } diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c2f4535164..0f509d2767 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -402,7 +402,7 @@ void Animation::updatePosition(Ogre::Vector3 &position) mAccumRoot->setPosition(-mLastPosition); } -bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop) +bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) { std::string tag = groupname+": "+start; NifOgre::TextKeyMap::const_iterator startkey(keys.begin()); @@ -432,9 +432,17 @@ bool Animation::reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre: mLayer[layeridx].mLoopStartKey = startkey; mLayer[layeridx].mStopKey = stopkey; mLayer[layeridx].mNextKey = startkey; - mLayer[layeridx].mNextKey++; - mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first; + mLayer[layeridx].mTime = mLayer[layeridx].mStartKey->first + ((mLayer[layeridx].mStopKey->first- + mLayer[layeridx].mStartKey->first) * startpoint); + + tag = groupname+": loop start"; + while(mLayer[layeridx].mNextKey->first <= mLayer[layeridx].mTime && mLayer[layeridx].mNextKey != mLayer[layeridx].mStopKey) + { + if(mLayer[layeridx].mNextKey->second == tag) + mLayer[layeridx].mLoopStartKey = mLayer[layeridx].mNextKey; + mLayer[layeridx].mNextKey++; + } if(layeridx == 0 && nonaccumctrl) mLastPosition = nonaccumctrl->getTranslation(mLayer[layeridx].mTime) * mAccumulate; @@ -507,7 +515,7 @@ bool Animation::handleTextKey(size_t layeridx, const NifOgre::TextKeyMap::const_ } -void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops) +void Animation::play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops) { // TODO: parameterize this size_t layeridx = 0; @@ -554,7 +562,7 @@ void Animation::play(const std::string &groupname, const std::string &start, con if(!foundanim) { - if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop)) + if(!reset(layeridx, keys, nonaccumctrl, groupname, start, stop, startpoint)) continue; mLayer[layeridx].mGroupName = groupname; mLayer[layeridx].mTextKeys = &keys; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 526bca69a8..d7f38545f5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -95,7 +95,10 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, NifOgre::NodeTargetValue *nonaccumctrl, const std::string &groupname, const std::string &start, const std::string &stop); + bool reset(size_t layeridx, const NifOgre::TextKeyMap &keys, + NifOgre::NodeTargetValue *nonaccumctrl, + const std::string &groupname, const std::string &start, const std::string &stop, + float startpoint); bool doLoop(size_t layeridx); @@ -123,7 +126,18 @@ public: void setSpeed(float speed); - void play(const std::string &groupname, const std::string &start, const std::string &stop, size_t loops); + /** Plays an animation. + * \param groupname Name of the animation group to play. + * \param start Key marker from which to start. + * \param stop Key marker to stop at. + * \param startpoint How far in between the two markers to start. 0 starts + * at the start marker, 1 starts at the stop marker. + * \param loops How many times to loop the animation. This will use the + * "loop start" and "loop stop" markers if they exist, + * otherwise it will use "start" and "stop". + */ + void play(const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, size_t loops); + virtual Ogre::Vector3 runAnimation(float timepassed); bool isPlaying(size_t layeridx) const diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c22d8a4da4..24b089db38 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -155,7 +155,7 @@ namespace MWRender if (!mSelectionBuffer) mSelectionBuffer = new OEngine::Render::SelectionBuffer(mCamera, 512, 1024, 0); - mAnimation->play("inventoryhandtohand", "start", "stop", 0); + mAnimation->play("inventoryhandtohand", "start", "stop", 0.0f, 0); } // -------------------------------------------------------------------------------------------------- @@ -189,7 +189,7 @@ namespace MWRender void RaceSelectionPreview::onSetup () { - mAnimation->play("idle", "start", "stop", 0); + mAnimation->play("idle", "start", "stop", 0.0f, 0); updateCamera(); } From 9e3917881d5d4f0b1c23c31d879369a06a9bc4bd Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 25 Apr 2013 04:44:30 +0200 Subject: [PATCH 0523/1537] Don't fail on nonexistent items in a levelled list --- apps/openmw/mwworld/containerstore.cpp | 85 ++++++++++++++------------ 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index 05026a98ba..5cf5342393 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -193,59 +193,68 @@ void MWWorld::ContainerStore::addInitialItem (const std::string& id, const std:: { count = std::abs(count); /// \todo implement item restocking (indicated by negative count) - ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - - if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) + try { - const ESM::ItemLevList* levItem = ref.getPtr().get()->mBase; - const std::vector& items = levItem->mList; + ManualRef ref (MWBase::Environment::get().getWorld()->getStore(), id); - MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); - int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); - - failChance += levItem->mChanceNone; - - if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) + if (ref.getPtr().getTypeName()==typeid (ESM::ItemLevList).name()) { - for (int i=0; i()->mBase; + const std::vector& items = levItem->mList; - float random = static_cast (std::rand()) / RAND_MAX; - if (random >= failChance/100.f) - { - std::vector candidates; - int highestLevel = 0; - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + int playerLevel = MWWorld::Class::get(player).getCreatureStats(player).getLevel(); + + failChance += levItem->mChanceNone; + + if (topLevel && count > 1 && levItem->mFlags & ESM::ItemLevList::Each) { - if (it->mLevel > highestLevel) - highestLevel = it->mLevel; + for (int i=0; i highest = std::make_pair(-1, ""); - for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + float random = static_cast (std::rand()) / RAND_MAX; + if (random >= failChance/100.f) { - if (playerLevel >= it->mLevel - && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + std::vector candidates; + int highestLevel = 0; + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) { - candidates.push_back(it->mId); - if (it->mLevel >= highest.first) - highest = std::make_pair(it->mLevel, it->mId); + if (it->mLevel > highestLevel) + highestLevel = it->mLevel; } + std::pair highest = std::make_pair(-1, ""); + for (std::vector::const_iterator it = items.begin(); it != items.end(); ++it) + { + if (playerLevel >= it->mLevel + && (levItem->mFlags & ESM::ItemLevList::AllLevels || it->mLevel == highestLevel)) + { + candidates.push_back(it->mId); + if (it->mLevel >= highest.first) + highest = std::make_pair(it->mLevel, it->mId); + } + + } + if (!candidates.size()) + return; + std::string item = candidates[std::rand()%candidates.size()]; + addInitialItem(item, owner, count, failChance, false); } - if (!candidates.size()) - return; - std::string item = candidates[std::rand()%candidates.size()]; - addInitialItem(item, owner, count, failChance, false); + } + else + { + ref.getPtr().getRefData().setCount (count); + ref.getPtr().getCellRef().mOwner = owner; + addImp (ref.getPtr()); } } - else + catch (std::logic_error& e) { - ref.getPtr().getRefData().setCount (count); - ref.getPtr().getCellRef().mOwner = owner; - addImp (ref.getPtr()); + // Vanilla doesn't fail on nonexistent items in levelled lists + std::cerr << "Warning: ignoring nonexistent item '" << id << "'" << std::endl; + return; } } From 03ee7663a3e89698c36108d03a7fcd036762d827 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 17:33:28 -0800 Subject: [PATCH 0524/1537] reworked NIFStream to use a type-handler Reworked NIFStream to use a type-handler system to decide how to extract data from the NIF. It also has the capability to perform bulk reads on compatible platforms, thus improving cell-load performance. --- components/nif/nifstream.hpp | 338 +++++++++++++++++++++++------------ 1 file changed, 225 insertions(+), 113 deletions(-) diff --git a/components/nif/nifstream.hpp b/components/nif/nifstream.hpp index a2595d17b8..7abfae9e84 100644 --- a/components/nif/nifstream.hpp +++ b/components/nif/nifstream.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP #define OPENMW_COMPONENTS_NIF_NIFSTREAM_HPP +#include + namespace Nif { @@ -11,168 +13,278 @@ class NIFStream { /// Input stream Ogre::DataStreamPtr inp; - uint8_t read_byte() + template + value_t read_le () { - uint8_t byte; - if(inp->read(&byte, 1) != 1) return 0; - return byte; - } - uint16_t read_le16() - { - uint8_t buffer[2]; - if(inp->read(buffer, 2) != 2) return 0; - return buffer[0] | (buffer[1]<<8); - } - uint32_t read_le32() - { - uint8_t buffer[4]; - if(inp->read(buffer, 4) != 4) return 0; - return buffer[0] | (buffer[1]<<8) | (buffer[2]<<16) | (buffer[3]<<24); - } - float read_le32f() - { - union { - uint32_t i; - float f; - } u = { read_le32() }; - return u.f; + uint8_t buffer [sizeof (value_t)]; + + if (inp->read (buffer, sizeof (buffer)) != sizeof (buffer)) + throw std::runtime_error ("unexpected"); + + value_t Value = 0; + value_t Shift = 0; + + for (size_t i = 0; i < sizeof (value_t); ++i) + { + Value |= value_t (buffer[i]) << Shift; + Shift += 8; + } + + return Value; } public: + /* + * This should be true for any processor/platform whose endianess, alignment + * and packing rules would be compatible with x86 and not fault or degrade + * with misaligned reads. This enables some pretty big savings when reading in + * animations and meshes. + */ +#if defined (__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) + static const bool FileCompatiblePlatform = true; +#else + static const bool FileCompatiblePlatform = false; +#endif + + template + struct handler; + + template + struct le_handler; + + template + friend struct le_handler; + + template + struct conversion_handler; + NIFFile * const file; - NIFStream (NIFFile * file, Ogre::DataStreamPtr inp): file (file), inp (inp) {} + NIFStream (NIFFile * file, Ogre::DataStreamPtr inp) : file (file), inp (inp) {} /************************************************* Parser functions ****************************************************/ - template - struct GetHandler - { - typedef T (NIFStream::*fn_t)(); - - static const fn_t sValue; // this is specialized per supported type in the .cpp file - - static T read (NIFStream* nif) - { - return (nif->*sValue) (); - } - }; + void skip(size_t size) { return inp->skip (size); } + size_t read (void * data, size_t size) { return inp->read (data, size); } template - void read (NIFStream* nif, T & Value) + void uncheckedRead (T & Value) { - Value = GetHandler ::read (nif); + typedef handler handler_t; + handler_t::extract (*this, Value); } - void skip(size_t size) { inp->skip(size); } - void read (void * data, size_t size) { inp->read (data, size); } + template + T getValue () + { + T Value; + getValue (Value); + return Value; + } - char getChar() { return read_byte(); } - short getShort() { return read_le16(); } - unsigned short getUShort() { return read_le16(); } - int getInt() { return read_le32(); } - int getUInt() { return read_le32(); } - float getFloat() { return read_le32f(); } - Ogre::Vector2 getVector2() + template + void getValue (T & Value) { - float a[2]; - for(size_t i = 0;i < 2;i++) - a[i] = getFloat(); - return Ogre::Vector2(a); - } - Ogre::Vector3 getVector3() - { - float a[3]; - for(size_t i = 0;i < 3;i++) - a[i] = getFloat(); - return Ogre::Vector3(a); - } - Ogre::Vector4 getVector4() - { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Vector4(a); - } - Ogre::Matrix3 getMatrix3() - { - Ogre::Real a[3][3]; - for(size_t i = 0;i < 3;i++) + typedef handler handler_t; + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) { - for(size_t j = 0;j < 3;j++) - a[i][j] = Ogre::Real(getFloat()); + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (T), "unexpected structure size"); + + inp->read (&Value, handler_t::EncodedLength); + } + else + { + handler_t::extract (*this, Value); } - return Ogre::Matrix3(a); } - Ogre::Quaternion getQuaternion() + + template + void getArray (element_type * Array, size_t Size) { - float a[4]; - for(size_t i = 0;i < 4;i++) - a[i] = getFloat(); - return Ogre::Quaternion(a); + typedef handler handler_t; + + if (FileCompatiblePlatform && handler_t::FileCompatibleLayout) + { + BOOST_STATIC_ASSERT_MSG (handler_t::FixedLength, "non-fixed length encoding not supported..."); + BOOST_STATIC_ASSERT_MSG (handler_t::EncodedLength == sizeof (element_type), "unexpected structure size"); + + inp->read (Array, handler_t::EncodedLength * Size); + } + else + { + for(size_t i = 0; i < Size; i++) + handler_t::extract (*this, Array[i]); + } } - Transformation getTrafo() + + template + void getStdVector (std::vector & Vector, size_t Size) { - Transformation t; - t.pos = getVector3(); - t.rotation = getMatrix3(); - t.scale = getFloat(); - return t; + Vector.resize(Size); + + getArray (&Vector.front (), Vector.size ()); } + template + void getStdVector (std::vector & Vector) + { + length_type Length; + + getValue (Length); + + getStdVector (Vector, Length); + } + + char getChar() { return getValue (); } + signed int getInt() { return getValue (); } + unsigned int getUInt() { return getValue (); } + signed short getShort() { return getValue (); } + unsigned short getUShort() { return getValue (); } + //signed long getLong() { return getValue (); } + //unsigned long getULong() { return getValue (); } + float getFloat() { return getValue (); } + + Ogre::Vector2 getVector2() { return getValue (); } + Ogre::Vector3 getVector3() { return getValue (); } + Ogre::Vector4 getVector4() { return getValue (); } + Ogre::Matrix3 getMatrix3() { return getValue (); } + Ogre::Quaternion getQuaternion() { return getValue (); } + + Transformation getTrafo() { return getValue (); } + + void getShorts(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getFloats(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector2s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector3s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getVector4s(std::vector &vec, size_t size) { return getStdVector (vec, size); } + void getQuaternions(std::vector &vec, size_t size) { return getStdVector (vec, size); } + std::string getString(size_t length) { std::vector str (length+1, 0); - if(inp->read(&str[0], length) != length) + if(read(&str[0], length) != length) throw std::runtime_error ("string length in NIF file does not match"); return &str[0]; } std::string getString() { - size_t size = read_le32(); + size_t size = getValue (); return getString(size); } +}; - void getShorts(std::vector &vec, size_t size) +/* + * generic type handlers + */ + +template +struct NIFStream::handler < type [Size] > +{ + typedef handler inner_handler; + + static const bool FixedLength = inner_handler::FixedLength; + static const size_t EncodedLength = inner_handler::EncodedLength * Size; + static const bool FileCompatibleLayout = inner_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, type (&Value) [Size]) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getShort(); + for (size_t i = 0; i < Size; ++i) + inner_handler::extract (Stream, Value [i]); } - void getFloats(std::vector &vec, size_t size) +}; + +template +struct NIFStream::le_handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = sizeof (backing_type); + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & Stream, presentation_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getFloat(); + BOOST_STATIC_ASSERT_MSG(sizeof (presentation_type) == sizeof (backing_type), "Invalid use of NIFile::le_handler template"); + + union { + + backing_type Backing; + presentation_type Presentation; + + } u; + + u.Backing = Stream.read_le (); + + Value = u.Presentation; } - void getVector2s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = false; + + static void extract (NIFStream & Stream, final_type & Value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector2(); + store_type StoreValue; + store_handler::extract (Stream, StoreValue); + Value = final_type (StoreValue); } - void getVector3s(std::vector &vec, size_t size) +}; + +template +struct NIFStream::conversion_handler +{ + typedef handler store_handler; + + static const bool FixedLength = store_handler::FixedLength; + static const size_t EncodedLength = store_handler::EncodedLength; + static const bool FileCompatibleLayout = store_handler::FileCompatibleLayout; + + static void extract (NIFStream & Stream, final_type & FinalValue) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector3(); + store_handler::extract (Stream, reinterpret_cast (FinalValue)); } - void getVector4s(std::vector &vec, size_t size) +}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::le_handler {}; +template <> struct NIFStream::handler : NIFStream::le_handler {}; + +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; +template <> struct NIFStream::handler : NIFStream::conversion_handler {}; + +template <> struct NIFStream::handler +{ + static const bool FixedLength = true; + static const size_t EncodedLength = + handler ::EncodedLength + + handler ::EncodedLength + + handler ::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream & stream, Transformation & value) { - vec.resize(size); - for(size_t i = 0;i < vec.size();i++) - vec[i] = getVector4(); - } - void getQuaternions(std::vector &quat, size_t size) - { - quat.resize(size); - for(size_t i = 0;i < quat.size();i++) - quat[i] = getQuaternion(); + stream.uncheckedRead (value.pos); + stream.uncheckedRead (value.rotation); + stream.uncheckedRead (value.scale); } }; From e7665582ad9b855522b37d955997df527254a01d Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sat, 5 Jan 2013 22:51:06 -0800 Subject: [PATCH 0525/1537] reworked Nif::KeyListT into Nif::CurveT Renamed Nif:KeyListT to Nif::CurveT, moved it into its own file and changed its implementation so that on compatible platforms, the entire array of key-frames can be read in a single read call. Added a helper class called Nif::CurveT::interpolator to allow other code to easily evaluate the curve. Reworked part of the skeletonLoader code to use the interpolator to simplify its own logic. --- components/nif/curve.hpp | 424 +++++++++++++++++++++++++++ components/nif/data.hpp | 17 +- components/nif/niffile.hpp | 76 ----- components/nifogre/ogrenifloader.cpp | 113 ++----- components/nifogre/skeleton.cpp | 107 ++----- 5 files changed, 481 insertions(+), 256 deletions(-) create mode 100644 components/nif/curve.hpp diff --git a/components/nif/curve.hpp b/components/nif/curve.hpp new file mode 100644 index 0000000000..9a71f0923d --- /dev/null +++ b/components/nif/curve.hpp @@ -0,0 +1,424 @@ +#ifndef _NIF_KEYLIST_H_ +#define _NIF_KEYLIST_H_ + +#include + +namespace Nif +{ + +template +void bubble_sort (iterator begin, iterator end, predicate const & in_order) +{ + if (end > begin) + { + for (iterator i = begin; i != end - 1; ++i) + { + if (in_order (*(i+0), *(i+1))) + continue; + + for (iterator j = i; j >= begin; --j) + { + std::swap (*(j+0), *(j+1)); + + if (in_order (*(j+0), *(j+1))) + break; + } + } + } +} + +template +value_type linear_interpolate (float amount, value_type prev, value_type next) +{ + return prev + (next - prev) * amount; +} + +inline +Ogre::Quaternion linear_interpolate (float amount, Ogre::Quaternion prev, Ogre::Quaternion next) +{ + return Ogre::Quaternion::nlerp (amount, prev, next); +} + +template +struct KeyT { + + static const size_t EncodedLength = + NIFStream::handler ::EncodedLength + + NIFStream::handler ::EncodedLength + ; + + float mTime; + value_type mValue; + + void extract (NIFStream &nif) + { + nif.uncheckedRead (mTime); + nif.uncheckedRead (mValue); + } + + static bool in_order (KeyT const & l, KeyT const & r) + { + return l.mTime < r.mTime; + } + + template + struct NIFStream_handler + { + static const bool FixedLength = true; + static const size_t EncodedLength = derived_type::EncodedLength; + static const bool FileCompatibleLayout = true; + + static void extract (NIFStream& Stream, KeyT & Value) + { + static_cast (Value).extract (Stream); + } + }; +}; + +template +struct LinearKeyT : KeyT +{ + static T interpolate (LinearKeyT * prev, LinearKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } +}; + +template +struct QuadraticKeyT : KeyT +{ + static const size_t EncodedLength = + KeyT ::EncodedLength + + NIFStream::handler ::EncodedLength * 2 + ; + + T mForwardValue; + T mBackwardValue; + + static T interpolate (QuadraticKeyT * prev, QuadraticKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } + + void extract (NIFStream &nif) + { + KeyT::extract (nif); + + nif.uncheckedRead (mForwardValue); + nif.uncheckedRead (mBackwardValue); + } +}; + +template +struct TbcKeyT : KeyT +{ + static const size_t EncodedLength = + KeyT ::EncodedLength + + NIFStream::handler ::EncodedLength * 3 + ; + + float mTension; + float mBias; + float mContinuity; + + static T interpolate (TbcKeyT * prev, TbcKeyT * next, float amount) + { + return linear_interpolate (amount, prev->mValue, next->mValue); + } + + void extract (NIFStream &nif) + { + KeyT::extract (nif); + + nif.uncheckedRead (mTension); + nif.uncheckedRead (mBias); + nif.uncheckedRead (mContinuity); + } +}; + +// register NIFStream extraction handlers for KeyT derivatives +template struct NIFStream::handler < LinearKeyT > : KeyT ::template NIFStream_handler < LinearKeyT > {}; +template struct NIFStream::handler < QuadraticKeyT > : KeyT ::template NIFStream_handler < QuadraticKeyT > {}; +template struct NIFStream::handler < TbcKeyT > : KeyT ::template NIFStream_handler < TbcKeyT > {}; + +struct Curve +{ + static const int sLinearInterpolation = 1; + static const int sQuadraticInterpolation = 2; + static const int sTBCInterpolation = 3; +}; + +template +struct CurveT : Curve { + + typedef KeyT BaseKey; + typedef TbcKeyT TcbKey; + typedef LinearKeyT LinearKey; + typedef QuadraticKeyT QuadraticKey; + + union keys { + LinearKey* Linear; + QuadraticKey* Quadratic; + TcbKey* Tcb; + }; + + class interpolator; + + int mInterpolationType; + size_t mSize; + keys mKeys; + + value_type sample (float time) const; + + KeyT const * const & keyAtIndex (size_t Index) const + { + switch (mInterpolationType) + { + case sLinearInterpolation: return mKeys.Linear + Index; + case sQuadraticInterpolation: return mKeys.Quadratic + Index; + case sTBCInterpolation: return mKeys.Tcb + Index; + } + } + + void read(NIFStream *nif, bool force=false) + { + size_t count = nif->getInt(); + + mSize = 0; + + if(count > 0 || force) + { + mInterpolationType = nif->getInt(); + + assert (mInterpolationType >= sLinearInterpolation && mInterpolationType <= sTBCInterpolation); + + if (count > 0) + { + if(mInterpolationType == sLinearInterpolation) + read_keys (nif, mKeys.Linear, count); + else if(mInterpolationType == sQuadraticInterpolation) + read_keys (nif, mKeys.Quadratic, count); + else if(mInterpolationType == sTBCInterpolation) + read_keys (nif, mKeys.Tcb, count); + else + nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); + } + } + else + mInterpolationType = sLinearInterpolation; + } + + CurveT () { init (); } + CurveT (CurveT const & k) { init (k); } + //CurveT (CurveT && k) { init (); swap (std::move (k)); } + ~CurveT () { dest (); } + + operator bool () const { return mSize > 0; } + + //void operator = (CurveT && k) { swap(k); } + void operator = (CurveT const & k) { dest (); init (k); } + + void swap (CurveT & k) + { + std::swap (mSize, k.mSize); + std::swap (mInterpolationType, k.mInterpolationType); + std::swap (mKeys, k.mKeys); + } + +private: + + void init () + { + mSize = 0; + } + + void init (CurveT const & k) + { + mInterpolationType = k.mInterpolationType; + switch (mInterpolationType) + { + default: + case sLinearInterpolation: + mKeys.Linear = new LinearKey [k.mSize]; + memcpy (mKeys.Linear, k.mKeys.Linear, sizeof (LinearKey) * k.mSize); + mSize = k.mSize; + break; + case sQuadraticInterpolation: + mKeys.Quadratic = new QuadraticKey [k.mSize]; + memcpy (mKeys.Quadratic, k.mKeys.Quadratic, sizeof (QuadraticKey) * k.mSize); + mSize = k.mSize; + break; + case sTBCInterpolation: + mKeys.Tcb = new TcbKey [k.mSize]; + memcpy (mKeys.Tcb, k.mKeys.Tcb, sizeof (TcbKey) * k.mSize); + mSize = k.mSize; + break; + } + } + + void dest () + { + if (mSize > 0) + { + switch (mInterpolationType) + { + case sLinearInterpolation: delete mKeys.Linear; break; + case sQuadraticInterpolation: delete mKeys.Quadratic; break; + case sTBCInterpolation: delete mKeys.Tcb; break; + } + } + } + + template + void read_keys (NIFStream *nif, T * & store, size_t count) + { + store = new T [count]; + + mSize = count; + + nif->getArray (store, count); + + //NOTE: Is this really necessary? It seems reasonable to assume that + // animation data is already sorted by time... + // verified no out of order frames in GOTY edition + bubble_sort (store, store+count, T::in_order); + } +}; + +template +class CurveT::interpolator +{ + template + struct impl + { + key_type *Cur, *End; + + void init (key_type * Beg, size_t Len) + { + if (Len > 0) + { + Cur = Beg; + End = Beg + Len - 1; + } + else + { + Cur = End = NULL; + } + } + + bool hasData () const + { + return Cur && Cur <= End; + } + + value_type valueAt (float time) + { + while ((Cur < End) && (time >= Cur [1].mTime)) + ++Cur; + + if (Cur < End) + { + if (time > Cur->mTime) + { + key_type * Nxt = Cur + 1; + + float offset = time - Cur->mTime; + float length = Nxt->mTime - Cur->mTime; + + return key_type::interpolate (Cur, Nxt, offset / length); + } + else + return Cur->mValue; + } + else + return End->mValue; + } + + float curTime () const + { + return (Cur != NULL) ? Cur->Time : FLT_MIN; + } + + float nextTime () const + { + return Cur < End ? (Cur + 1)->mTime : FLT_MAX; + } + }; + +public: + + int mInterpolationType; + union { + impl Linear; + impl Quadratic; + impl Tcb; + }; + + interpolator (CurveT const & Curve) + { + mInterpolationType = Curve.mInterpolationType; + + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: Linear .init (Curve.mKeys.Linear, Curve.mSize); break; + case Curve::sQuadraticInterpolation: Quadratic.init (Curve.mKeys.Quadratic, Curve.mSize); break; + case Curve::sTBCInterpolation: Tcb .init (Curve.mKeys.Tcb, Curve.mSize); break; + } + } + + // return true if there is any value(s) in this curve + float hasData () const + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .hasData (); + case Curve::sQuadraticInterpolation: return Quadratic.hasData (); + case Curve::sTBCInterpolation: return Tcb .hasData (); + } + } + + // return the timestamp of the next key-frame, or FLT_MAX if + // there are no more key-frames, valid if hasData returns false + float nextTime () const + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .nextTime (); + case Curve::sQuadraticInterpolation: return Quadratic.nextTime (); + case Curve::sTBCInterpolation: return Tcb .nextTime (); + } + } + + // return the value of the curve at the specified time + // the passed in time should never exceed the result of + // nextTime, not valid if hasData returns false + value_type valueAt (float time) + { + switch (mInterpolationType) + { + default: + case Curve::sLinearInterpolation: return Linear .valueAt (time); + case Curve::sQuadraticInterpolation: return Quadratic.valueAt (time); + case Curve::sTBCInterpolation: return Tcb .valueAt (time); + } + } +}; + +template +value_type CurveT::sample (float time) const +{ + interpolator i (*this); + return i.valueAt (time); +} + +typedef CurveT FloatCurve; +typedef CurveT Vector3Curve; +typedef CurveT Vector4Curve; +typedef CurveT QuaternionCurve; + +} + +#endif diff --git a/components/nif/data.hpp b/components/nif/data.hpp index f1f34184ba..d46f99abbc 100644 --- a/components/nif/data.hpp +++ b/components/nif/data.hpp @@ -25,6 +25,7 @@ #define OPENMW_COMPONENTS_NIF_DATA_HPP #include "controlled.hpp" +#include "curve.hpp" #include #include @@ -211,7 +212,7 @@ public: class NiPosData : public Record { public: - Vector3KeyList mKeyList; + Vector3Curve mKeyList; void read(NIFStream *nif) { @@ -222,7 +223,7 @@ public: class NiUVData : public Record { public: - FloatKeyList mKeyList[4]; + FloatCurve mKeyList[4]; void read(NIFStream *nif) { @@ -234,7 +235,7 @@ public: class NiFloatData : public Record { public: - FloatKeyList mKeyList; + FloatCurve mKeyList; void read(NIFStream *nif) { @@ -284,7 +285,7 @@ public: class NiColorData : public Record { public: - Vector4KeyList mKeyList; + Vector4Curve mKeyList; void read(NIFStream *nif) { @@ -389,7 +390,7 @@ public: struct NiMorphData : public Record { struct MorphData { - FloatKeyList mData; + FloatCurve mData; std::vector mVertices; }; std::vector mMorphs; @@ -412,9 +413,9 @@ struct NiMorphData : public Record struct NiKeyframeData : public Record { - QuaternionKeyList mRotations; - Vector3KeyList mTranslations; - FloatKeyList mScales; + QuaternionCurve mRotations; + Vector3Curve mTranslations; + FloatCurve mScales; void read(NIFStream *nif) { diff --git a/components/nif/niffile.hpp b/components/nif/niffile.hpp index 6e629772e6..83cc6ac8fd 100644 --- a/components/nif/niffile.hpp +++ b/components/nif/niffile.hpp @@ -132,81 +132,5 @@ public: size_t numRoots() { return roots.size(); } }; - -template -struct KeyT { - float mTime; - T mValue; - T mForwardValue; // Only for Quadratic interpolation - T mBackwardValue; // Only for Quadratic interpolation - float mTension; // Only for TBC interpolation - float mBias; // Only for TBC interpolation - float mContinuity; // Only for TBC interpolation -}; -typedef KeyT FloatKey; -typedef KeyT Vector3Key; -typedef KeyT Vector4Key; -typedef KeyT QuaternionKey; - -template -struct KeyListT { - typedef std::vector< KeyT > VecType; - - static const int sLinearInterpolation = 1; - static const int sQuadraticInterpolation = 2; - static const int sTBCInterpolation = 3; - - int mInterpolationType; - VecType mKeys; - - void read(NIFStream *nif, bool force=false) - { - size_t count = nif->getInt(); - if(count == 0 && !force) - return; - - mInterpolationType = nif->getInt(); - mKeys.resize(count); - if(mInterpolationType == sLinearInterpolation) - { - for(size_t i = 0;i < count;i++) - { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - } - } - else if(mInterpolationType == sQuadraticInterpolation) - { - for(size_t i = 0;i < count;i++) - { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - key.mForwardValue = (nif->*getValue)(); - key.mBackwardValue = (nif->*getValue)(); - } - } - else if(mInterpolationType == sTBCInterpolation) - { - for(size_t i = 0;i < count;i++) - { - KeyT &key = mKeys[i]; - key.mTime = nif->getFloat(); - key.mValue = (nif->*getValue)(); - key.mTension = nif->getFloat(); - key.mBias = nif->getFloat(); - key.mContinuity = nif->getFloat(); - } - } - else - nif->file->warn("Unhandled interpolation type: "+Ogre::StringConverter::toString(mInterpolationType)); - } -}; -typedef KeyListT FloatKeyList; -typedef KeyListT Vector3KeyList; -typedef KeyListT Vector4KeyList; -typedef KeyListT QuaternionKeyList; - } // Namespace #endif diff --git a/components/nifogre/ogrenifloader.cpp b/components/nifogre/ogrenifloader.cpp index a26f431311..f381dc239f 100644 --- a/components/nifogre/ogrenifloader.cpp +++ b/components/nifogre/ogrenifloader.cpp @@ -166,9 +166,9 @@ public: class Value : public NodeTargetValue { private: - Nif::QuaternionKeyList mRotations; - Nif::Vector3KeyList mTranslations; - Nif::FloatKeyList mScales; + Nif::QuaternionCurve mRotations; + Nif::Vector3Curve mTranslations; + Nif::FloatCurve mScales; public: Value(Ogre::Node *target, const Nif::NiKeyframeData *data) @@ -186,68 +186,16 @@ public: virtual void setValue(Ogre::Real time) { - if(mRotations.mKeys.size() > 0) - { - if(time <= mRotations.mKeys.front().mTime) - mNode->setOrientation(mRotations.mKeys.front().mValue); - else if(time >= mRotations.mKeys.back().mTime) - mNode->setOrientation(mRotations.mKeys.back().mValue); - else - { - Nif::QuaternionKeyList::VecType::const_iterator iter(mRotations.mKeys.begin()+1); - for(;iter != mRotations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; + if(mRotations) + mNode->setOrientation(mRotations.sample (time)); - Nif::QuaternionKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setOrientation(Ogre::Quaternion::nlerp(a, last->mValue, iter->mValue)); - break; - } - } - } - if(mTranslations.mKeys.size() > 0) - { - if(time <= mTranslations.mKeys.front().mTime) - mNode->setPosition(mTranslations.mKeys.front().mValue); - else if(time >= mTranslations.mKeys.back().mTime) - mNode->setPosition(mTranslations.mKeys.back().mValue); - else - { - Nif::Vector3KeyList::VecType::const_iterator iter(mTranslations.mKeys.begin()+1); - for(;iter != mTranslations.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; + if(mTranslations) + mNode->setPosition(mTranslations.sample (time)); - Nif::Vector3KeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setPosition(last->mValue + ((iter->mValue - last->mValue)*a)); - break; - } - } - } - if(mScales.mKeys.size() > 0) + if(mScales) { - if(time <= mScales.mKeys.front().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.front().mValue)); - else if(time >= mScales.mKeys.back().mTime) - mNode->setScale(Ogre::Vector3(mScales.mKeys.back().mValue)); - else - { - Nif::FloatKeyList::VecType::const_iterator iter(mScales.mKeys.begin()+1); - for(;iter != mScales.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - mNode->setScale(Ogre::Vector3(last->mValue + ((iter->mValue - last->mValue)*a))); - break; - } - } + float s = mScales.sample (time); + mNode->setScale(s, s, s); } } }; @@ -262,30 +210,14 @@ public: { private: Ogre::MaterialPtr mMaterial; - Nif::FloatKeyList mUTrans; - Nif::FloatKeyList mVTrans; - Nif::FloatKeyList mUScale; - Nif::FloatKeyList mVScale; + Nif::FloatCurve mUTrans; + Nif::FloatCurve mVTrans; + Nif::FloatCurve mUScale; + Nif::FloatCurve mVScale; - static float lookupValue(const Nif::FloatKeyList &keys, float time, float def) + static float lookupValue(const Nif::FloatCurve &keys, float time, float def) { - if(keys.mKeys.size() == 0) - return def; - - if(time <= keys.mKeys.front().mTime) - return keys.mKeys.front().mValue; - - Nif::FloatKeyList::VecType::const_iterator iter(keys.mKeys.begin()+1); - for(;iter != keys.mKeys.end();iter++) - { - if(iter->mTime < time) - continue; - - Nif::FloatKeyList::VecType::const_iterator last(iter-1); - float a = (time-last->mTime) / (iter->mTime-last->mTime); - return last->mValue + ((iter->mValue - last->mValue)*a); - } - return keys.mKeys.back().mValue; + return keys ? keys.sample (time) : def; } public: @@ -392,18 +324,19 @@ class NIFObjectLoader const Nif::NiColorData *clrdata = cl->data.getPtr(); Ogre::ParticleAffector *affector = partsys->addAffector("ColourInterpolator"); - size_t num_colors = std::min(6, clrdata->mKeyList.mKeys.size()); + size_t num_colors = std::min(6, clrdata->mKeyList.mSize); for(size_t i = 0;i < num_colors;i++) { + Nif::Vector4Curve::BaseKey const * Key = clrdata->mKeyList.keyAtIndex (i); Ogre::ColourValue color; - color.r = clrdata->mKeyList.mKeys[i].mValue[0]; - color.g = clrdata->mKeyList.mKeys[i].mValue[1]; - color.b = clrdata->mKeyList.mKeys[i].mValue[2]; - color.a = clrdata->mKeyList.mKeys[i].mValue[3]; + color.r = Key->mValue[0]; + color.g = Key->mValue[1]; + color.b = Key->mValue[2]; + color.a = Key->mValue[3]; affector->setParameter("colour"+Ogre::StringConverter::toString(i), Ogre::StringConverter::toString(color)); affector->setParameter("time"+Ogre::StringConverter::toString(i), - Ogre::StringConverter::toString(clrdata->mKeyList.mKeys[i].mTime)); + Ogre::StringConverter::toString(Key->mTime)); } } else if(e->recType == Nif::RC_NiParticleRotation) diff --git a/components/nifogre/skeleton.cpp b/components/nifogre/skeleton.cpp index e97e91ef03..66060b9676 100644 --- a/components/nifogre/skeleton.cpp +++ b/components/nifogre/skeleton.cpp @@ -10,6 +10,11 @@ namespace NifOgre { +template +static value_type min (value_type V0, value_type V1, value_type V2, value_type V3) +{ + return std::min (std::min (V0, V1), std::min (V2, V3)); +} void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string &name, const std::vector &ctrls, const std::vector &targets, float startTime, float stopTime) { @@ -22,15 +27,6 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string & continue; const Nif::NiKeyframeData *kf = kfc->data.getPtr(); - /* Get the keyframes and make sure they're sorted first to last */ - const Nif::QuaternionKeyList &quatkeys = kf->mRotations; - const Nif::Vector3KeyList &trankeys = kf->mTranslations; - const Nif::FloatKeyList &scalekeys = kf->mScales; - - Nif::QuaternionKeyList::VecType::const_iterator quatiter = quatkeys.mKeys.begin(); - Nif::Vector3KeyList::VecType::const_iterator traniter = trankeys.mKeys.begin(); - Nif::FloatKeyList::VecType::const_iterator scaleiter = scalekeys.mKeys.begin(); - Ogre::Bone *bone = skel->getBone(targets[i]); // NOTE: For some reason, Ogre doesn't like the node track ID being different from // the bone ID @@ -38,83 +34,30 @@ void NIFSkeletonLoader::buildAnimation(Ogre::Skeleton *skel, const std::string & anim->getNodeTrack(bone->getHandle()) : anim->createNodeTrack(bone->getHandle(), bone); - Ogre::Quaternion lastquat, curquat; - Ogre::Vector3 lasttrans(0.0f), curtrans(0.0f); - Ogre::Vector3 lastscale(1.0f), curscale(1.0f); - if(quatiter != quatkeys.mKeys.end()) - lastquat = curquat = quatiter->mValue; - if(traniter != trankeys.mKeys.end()) - lasttrans = curtrans = traniter->mValue; - if(scaleiter != scalekeys.mKeys.end()) - lastscale = curscale = Ogre::Vector3(scaleiter->mValue); + Nif::QuaternionCurve::interpolator rci (kf->mRotations); + Nif::Vector3Curve::interpolator tci (kf->mTranslations); + Nif::FloatCurve::interpolator sci (kf->mScales); - bool didlast = false; - while(!didlast) + float next_timestamp = startTime; + + for (;;) { - float curtime = std::numeric_limits::max(); - - //Get latest time - if(quatiter != quatkeys.mKeys.end()) - curtime = std::min(curtime, quatiter->mTime); - if(traniter != trankeys.mKeys.end()) - curtime = std::min(curtime, traniter->mTime); - if(scaleiter != scalekeys.mKeys.end()) - curtime = std::min(curtime, scaleiter->mTime); - - curtime = std::max(curtime, startTime); - if(curtime >= stopTime) - { - didlast = true; - curtime = stopTime; - } - - // Get the latest quaternions, translations, and scales for the - // current time - while(quatiter != quatkeys.mKeys.end() && curtime >= quatiter->mTime) - { - lastquat = curquat; - if(++quatiter != quatkeys.mKeys.end()) - curquat = quatiter->mValue; - } - while(traniter != trankeys.mKeys.end() && curtime >= traniter->mTime) - { - lasttrans = curtrans; - if(++traniter != trankeys.mKeys.end()) - curtrans = traniter->mValue; - } - while(scaleiter != scalekeys.mKeys.end() && curtime >= scaleiter->mTime) - { - lastscale = curscale; - if(++scaleiter != scalekeys.mKeys.end()) - curscale = Ogre::Vector3(scaleiter->mValue); - } + static const Ogre::Vector3 one (1,1,1); Ogre::TransformKeyFrame *kframe; - kframe = nodetrack->createNodeKeyFrame(curtime); - if(quatiter == quatkeys.mKeys.end() || quatiter == quatkeys.mKeys.begin()) - kframe->setRotation(curquat); - else - { - Nif::QuaternionKeyList::VecType::const_iterator last = quatiter-1; - float diff = (curtime-last->mTime) / (quatiter->mTime-last->mTime); - kframe->setRotation(Ogre::Quaternion::nlerp(diff, lastquat, curquat)); - } - if(traniter == trankeys.mKeys.end() || traniter == trankeys.mKeys.begin()) - kframe->setTranslate(curtrans); - else - { - Nif::Vector3KeyList::VecType::const_iterator last = traniter-1; - float diff = (curtime-last->mTime) / (traniter->mTime-last->mTime); - kframe->setTranslate(lasttrans + ((curtrans-lasttrans)*diff)); - } - if(scaleiter == scalekeys.mKeys.end() || scaleiter == scalekeys.mKeys.begin()) - kframe->setScale(curscale); - else - { - Nif::FloatKeyList::VecType::const_iterator last = scaleiter-1; - float diff = (curtime-last->mTime) / (scaleiter->mTime-last->mTime); - kframe->setScale(lastscale + ((curscale-lastscale)*diff)); - } + kframe = nodetrack->createNodeKeyFrame (next_timestamp); + + if (rci.hasData ()) kframe->setRotation (rci.valueAt (next_timestamp)); + if (tci.hasData ()) kframe->setTranslate (tci.valueAt (next_timestamp)); + if (sci.hasData ()) kframe->setScale (sci.valueAt (next_timestamp)*one); + + if (next_timestamp >= stopTime) + break; + + next_timestamp = min (stopTime, + rci.nextTime (), + tci.nextTime (), + sci.nextTime ()); } } anim->optimise(); From 6dbb53493b34c6430e8bdf0ea0d4f411facfa1b5 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Thu, 3 Jan 2013 23:39:00 -0800 Subject: [PATCH 0526/1537] enable move construction/assignment to key ESM data structure to reduce sorting costs --- components/esm/defs.hpp | 10 +++++++ components/esm/loaddial.hpp | 36 ++++++++++++++++++++++ components/esm/loadinfo.hpp | 60 +++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index bd86f9ba03..3dc498a639 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -1,6 +1,16 @@ #ifndef OPENMW_ESM_DEFS_H #define OPENMW_ESM_DEFS_H +#if _MSC_VER >= 1600 +#define OPENMW_ESM_ENABLE_CPP11_MOVE +#define OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(Class) \ + Class () {} \ + Class (Class const & that) { copy (*this, that); } \ + Class (Class && that) { move (*this, that); } \ + Class & operator = (Class const & that) { copy (*this, that); return *this; } \ + Class & operator = (Class && that) { move (*this, that); return *this; } +#endif + #include namespace ESM diff --git a/components/esm/loaddial.hpp b/components/esm/loaddial.hpp index 61f3f763de..bb726b8557 100644 --- a/components/esm/loaddial.hpp +++ b/components/esm/loaddial.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "loadinfo.hpp" @@ -35,6 +36,41 @@ struct Dialogue void load(ESMReader &esm); void save(ESMWriter &esm); + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(Dialogue) + + static void copy (Dialogue & d, Dialogue const & s) + { + d.mId = s.mId; + d.mType = s.mType; + d.mInfo = s.mInfo; + } + static void move (Dialogue & d, Dialogue & s) + { + d.mId = std::move (s.mId); + d.mType = std::move (s.mType); + d.mInfo = std::move (s.mInfo); + } +#endif }; } + +/* + custom swap to prevent memory allocations and deallocations for mId and mInfo + while sorting +*/ +namespace std +{ + template <> inline + void swap (ESM::Dialogue & Left, ESM::Dialogue & Right) + { +#define _swp(id) std::swap (Left.id, Right.id); + _swp(mId); + _swp(mType); + _swp(mInfo); +#undef _swp + } +} + #endif diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index 2361ed9eb5..c7608ca866 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -43,6 +43,22 @@ struct DialInfo { std::string mSelectRule; // This has a complicated format Variant mValue; + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(SelectStruct) + + static void copy (SelectStruct & d, SelectStruct const & s) + { + d.mSelectRule = s.mSelectRule; + d.mValue = s.mValue; + } + + static void move (SelectStruct & d, SelectStruct & s) + { + d.mSelectRule = std::move (s.mSelectRule); + d.mValue = std::move (s.mValue); + } +#endif // OPENMW_ESM_ENABLE_CPP11_MOVE }; // Journal quest indices (introduced with the quest system in Tribunal) @@ -100,6 +116,50 @@ struct DialInfo void load(ESMReader &esm); void save(ESMWriter &esm); + +#ifdef OPENMW_ESM_ENABLE_CPP11_MOVE + OPENMW_ESM_DEFINE_CPP11_MOVE_OPS(DialInfo) + + static void copy (DialInfo & d, DialInfo const & s) + { + d.mData = s.mData; + d.mSelects = s.mSelects; + d.mId = s.mId; + d.mPrev = s.mPrev; + d.mNext = s.mNext; + d.mActor = s.mActor; + d.mRace = s.mRace; + d.mClass = s.mClass; + d.mNpcFaction = s.mNpcFaction; + d.mPcFaction = s.mPcFaction; + d.mCell = s.mCell; + d.mSound = s.mSound; + d.mResponse = s.mResponse; + d.mResultScript = s.mResultScript; + d.mFactionLess = s.mFactionLess; + d.mQuestStatus = s.mQuestStatus; + } + + static void move (DialInfo & d, DialInfo & s) + { + d.mData = std::move (s.mData); + d.mSelects = std::move (s.mSelects); + d.mId = std::move (s.mId); + d.mPrev = std::move (s.mPrev); + d.mNext = std::move (s.mNext); + d.mActor = std::move (s.mActor); + d.mRace = std::move (s.mRace); + d.mClass = std::move (s.mClass); + d.mNpcFaction = std::move (s.mNpcFaction); + d.mPcFaction = std::move (s.mPcFaction); + d.mCell = std::move (s.mCell); + d.mSound = std::move (s.mSound); + d.mResponse = std::move (s.mResponse); + d.mResultScript = std::move (s.mResultScript); + d.mFactionLess = std::move (s.mFactionLess); + d.mQuestStatus = std::move (s.mQuestStatus); + } +#endif // OPENMW_ESM_ENABLE_CPP11_MOVE }; } From 8dad04eef19e7471787615348181d6c32ed6e82a Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 13 Jan 2013 13:03:11 -0800 Subject: [PATCH 0527/1537] hid JournalWindow behind IJournalWindow interface, and put its entire implementation, class definition and all, into journalwindow.cpp --- apps/openmw/mwgui/journalwindow.cpp | 223 ++++++++++++++----------- apps/openmw/mwgui/journalwindow.hpp | 34 +--- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 4 +- 4 files changed, 137 insertions(+), 126 deletions(-) diff --git a/apps/openmw/mwgui/journalwindow.cpp b/apps/openmw/mwgui/journalwindow.cpp index 23588a4afa..9540e69868 100644 --- a/apps/openmw/mwgui/journalwindow.cpp +++ b/apps/openmw/mwgui/journalwindow.cpp @@ -5,6 +5,16 @@ #include "../mwbase/journal.hpp" #include "../mwbase/soundmanager.hpp" +#include +#include +#include +#include + +#include "windowbase.hpp" +#include "imagebutton.hpp" + +using namespace MWGui; + namespace { struct book @@ -77,116 +87,135 @@ book formatText(std::string text,book mBook,int maxLine, int lineSize) //std::string } - -MWGui::JournalWindow::JournalWindow () - : WindowBase("openmw_journal.layout") - , mPageNumber(0) +namespace { - mMainWidget->setVisible(false); - //setCoord(0,0,498, 342); - center(); - - getWidget(mLeftTextWidget, "LeftText"); - getWidget(mRightTextWidget, "RightText"); - getWidget(mPrevBtn, "PrevPageBTN"); - mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyPrevPage); - getWidget(mNextBtn, "NextPageBTN"); - mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&MWGui::JournalWindow::notifyNextPage); - //MyGUI::ItemBox* list = new MyGUI::ItemBox(); - //list->addItem("qaq","aqzazaz"); - //mScrollerWidget->addChildItem(list); - //mScrollerWidget->addItem("dserzt",MyGUI::UString("fedgdfg")); - //mEditWidget->addText("ljblsxdvdsfvgedfvdfvdkjfghldfjgn sdv,nhsxl;vvn lklksbvlksb lbsdflkbdSLKJGBLskdhbvlshow(); - //mEditWidget->setEditStatic(true); - mLeftTextWidget->addText("left texxxt "); - mLeftTextWidget->setEditReadOnly(true); - mRightTextWidget->setEditReadOnly(true); - mRightTextWidget->setEditStatic(true); - mLeftTextWidget->setEditStatic(true); - mRightTextWidget->addText("Right texxt "); - - //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()); -} - -void MWGui::JournalWindow::open() -{ - mPageNumber = 0; - if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) + struct JournalWindow : WindowBase, IJournalWindow { - book journal; - journal.endLine = 0; + MyGUI::EditPtr mLeftTextWidget; + MyGUI::EditPtr mRightTextWidget; + MWGui::ImageButton* mPrevBtn; + MWGui::ImageButton* mNextBtn; + std::vector mLeftPages; + std::vector mRightPages; + int mPageNumber; //store the number of the current left page - for(std::deque::const_iterator it = MWBase::Environment::get().getJournal()->begin();it!=MWBase::Environment::get().getJournal()->end();++it) + JournalWindow () + : WindowBase("openmw_journal.layout") + , mPageNumber(0) { - std::string a = it->getText(MWBase::Environment::get().getWorld()->getStore()); - journal = formatText(a,journal,10,17); - journal.endLine = journal.endLine +1; - journal.pages.back() = journal.pages.back() + std::string("\n"); + mMainWidget->setVisible(false); + //setCoord(0,0,498, 342); + center(); + + getWidget(mLeftTextWidget, "LeftText"); + getWidget(mRightTextWidget, "RightText"); + getWidget(mPrevBtn, "PrevPageBTN"); + mPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyPrevPage); + getWidget(mNextBtn, "NextPageBTN"); + mNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this,&JournalWindow::notifyNextPage); + + + + mLeftTextWidget->setEditReadOnly(true); + mRightTextWidget->setEditReadOnly(true); + mRightTextWidget->setEditStatic(true); + mLeftTextWidget->setEditStatic(true); } - //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) + + void close() { - if(left) + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); + } + + void open() + { + mPageNumber = 0; + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); + if(MWBase::Environment::get().getJournal()->begin()!=MWBase::Environment::get().getJournal()->end()) { - mLeftPages.push_back(*it); + book journal; + journal.endLine = 0; + + 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); + journal.endLine = journal.endLine +1; + journal.pages.back() = journal.pages.back() + std::string("\n"); + } + //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) + { + if(left) + { + mLeftPages.push_back(*it); + } + else + { + mRightPages.push_back(*it); + } + left = !left; + } + if(!left) mRightPages.push_back(""); + + mPageNumber = mLeftPages.size()-1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } else { - mRightPages.push_back(*it); + //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); } - left = !left; } - if(!left) mRightPages.push_back(""); - mPageNumber = mLeftPages.size()-1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); + void setVisible (bool newValue) + { + WindowBase::setVisible (newValue); + } - } - else - { - //std::cout << MWBase::Environment::get().getJournal()->begin()->getText(MWBase::Environment::get().getWorld()->getStore()); - } + + void displayLeftText(std::string text) + { + mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); + mLeftTextWidget->addText(text); + } + + void displayRightText(std::string text) + { + mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); + mRightTextWidget->addText(text); + } + + + + void notifyNextPage(MyGUI::Widget* _sender) + { + if(mPageNumber < int(mLeftPages.size())-1) + { + std::string nextSound = "book page2"; + MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); + mPageNumber = mPageNumber + 1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } + } + + void notifyPrevPage(MyGUI::Widget* _sender) + { + if(mPageNumber > 0) + { + std::string prevSound = "book page"; + MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); + mPageNumber = mPageNumber - 1; + displayLeftText(mLeftPages[mPageNumber]); + displayRightText(mRightPages[mPageNumber]); + } + } + }; } -void MWGui::JournalWindow::displayLeftText(std::string text) -{ - mLeftTextWidget->eraseText(0,mLeftTextWidget->getTextLength()); - mLeftTextWidget->addText(text); -} - -void MWGui::JournalWindow::displayRightText(std::string text) -{ - mRightTextWidget->eraseText(0,mRightTextWidget->getTextLength()); - mRightTextWidget->addText(text); -} - - -void MWGui::JournalWindow::notifyNextPage(MyGUI::Widget* _sender) -{ - if(mPageNumber < int(mLeftPages.size())-1) - { - std::string nextSound = "book page2"; - MWBase::Environment::get().getSoundManager()->playSound (nextSound, 1.0, 1.0); - mPageNumber = mPageNumber + 1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); - } -} - -void MWGui::JournalWindow::notifyPrevPage(MyGUI::Widget* _sender) -{ - if(mPageNumber > 0) - { - std::string prevSound = "book page"; - MWBase::Environment::get().getSoundManager()->playSound (prevSound, 1.0, 1.0); - mPageNumber = mPageNumber - 1; - displayLeftText(mLeftPages[mPageNumber]); - displayRightText(mRightPages[mPageNumber]); - } -} +// glue the implementation to the interface +IJournalWindow * MWGui::IJournalWindow::create () { return new JournalWindow (); } diff --git a/apps/openmw/mwgui/journalwindow.hpp b/apps/openmw/mwgui/journalwindow.hpp index 27bf608e18..8f734dc244 100644 --- a/apps/openmw/mwgui/journalwindow.hpp +++ b/apps/openmw/mwgui/journalwindow.hpp @@ -1,39 +1,21 @@ #ifndef MWGUI_JOURNAL_H #define MWGUI_JOURNAL_H -#include - -#include "windowbase.hpp" -#include "imagebutton.hpp" +namespace MWBase { class WindowManager; } namespace MWGui { - class JournalWindow : public WindowBase + struct IJournalWindow { - public: - JournalWindow(); - virtual void open(); + /// construct a new instance of the one JournalWindow implementation + static IJournalWindow * create (); - private: - void displayLeftText(std::string text); - void displayRightText(std::string text); + /// destroy this instance of the JournalWindow implementation + virtual ~IJournalWindow () {}; - - /** - *Called when next/prev button is used. - */ - void notifyNextPage(MyGUI::Widget* _sender); - void notifyPrevPage(MyGUI::Widget* _sender); - - MyGUI::EditBox* mLeftTextWidget; - MyGUI::EditBox* mRightTextWidget; - MWGui::ImageButton* mPrevBtn; - MWGui::ImageButton* mNextBtn; - std::vector mLeftPages; - std::vector mRightPages; - int mPageNumber; //store the number of the current left page + /// show/hide the journal window + virtual void setVisible (bool newValue) = 0; }; - } #endif diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2171beaffb..6b38042a67 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -145,7 +145,7 @@ namespace MWGui mMap = new MapWindow(cacheDir); mStatsWindow = new StatsWindow(); mConsole = new Console(w,h, consoleOnlyScripts); - mJournal = new JournalWindow(); + mJournal = IJournalWindow::create(); mMessageBoxManager = new MessageBoxManager(); mInventoryWindow = new InventoryWindow(mDragAndDrop); mTradeWindow = new TradeWindow(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 652ad870f3..43951d46a8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -51,7 +51,7 @@ namespace MWGui class MainMenu; class StatsWindow; class InventoryWindow; - class JournalWindow; + class IJournalWindow; class CharacterCreation; class DragAndDrop; class ToolTips; @@ -253,7 +253,7 @@ namespace MWGui StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *mConsole; - JournalWindow* mJournal; + IJournalWindow* mJournal; DialogueWindow *mDialogueWindow; ContainerWindow *mContainerWindow; DragAndDrop* mDragAndDrop; From 85595245abb777dc038785a42afbb3781e570238 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 01:00:11 -0800 Subject: [PATCH 0528/1537] Updated journal layout to match Bethesda's version more closely --- files/mygui/openmw_journal.layout | 94 +++++++++++++++++++++++++------ 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/files/mygui/openmw_journal.layout b/files/mygui/openmw_journal.layout index fdf82e4dee..addd4296d7 100644 --- a/files/mygui/openmw_journal.layout +++ b/files/mygui/openmw_journal.layout @@ -2,24 +2,84 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 75757cb675f91b3e010221cb9687842c70f89009 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 10:43:41 -0800 Subject: [PATCH 0529/1537] Created a class to represent a stream of UTF8 characters. --- components/misc/utf8stream.hpp | 115 +++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 components/misc/utf8stream.hpp diff --git a/components/misc/utf8stream.hpp b/components/misc/utf8stream.hpp new file mode 100644 index 0000000000..a491ed0824 --- /dev/null +++ b/components/misc/utf8stream.hpp @@ -0,0 +1,115 @@ +#ifndef MISC_UTF8ITER_HPP +#define MISC_UTF8ITER_HPP + +#include + +class utf8_stream +{ +public: + + typedef uint32_t unicode_char; + typedef unsigned char const * point; + + static const unicode_char sBadChar = 0xFFFFFFFF; + + utf8_stream (point begin, point end) : + cur (begin), nxt (begin), end (end) + { + } + + utf8_stream (std::pair range) : + cur (range.first), nxt (range.first), end (range.second) + { + } + + bool eof () const + { + return cur == end; + } + + point current () const + { + return cur; + } + + unicode_char peek () + { + if (cur == nxt) + next (); + return val; + } + + unicode_char consume () + { + if (cur == nxt) + next (); + cur = nxt; + return val; + } + + static std::pair decode (point cur, point end) + { + if ((*cur & 0x80) == 0) + { + unicode_char chr = *cur++; + + return std::make_pair (chr, cur); + } + + int octets; + unicode_char chr; + + boost::tie (octets, chr) = octet_count (*cur++); + + if (octets > 5) + return std::make_pair (sBadChar, cur); + + auto eoc = cur + octets; + + if (eoc > end) + return std::make_pair (sBadChar, cur); + + while (cur != eoc) + { + if ((*cur & 0xC0) != 0x80) // check continuation mark + return std::make_pair (sBadChar, cur);; + + chr = (chr << 6) | unicode_char ((*cur++) & 0x3F); + } + + return std::make_pair (chr, cur); + } + +private: + + static std::pair octet_count (unsigned char octet) + { + int octets; + + unsigned char mark = 0xC0; + unsigned char mask = 0xE0; + + for (octets = 1; octets <= 5; ++octets) + { + if ((octet & mask) == mark) + break; + + mark = (mark >> 1) | 0x80; + mask = (mask >> 1) | 0x80; + } + + return std::make_pair (octets, octet & ~mask); + } + + void next () + { + boost::tie (val, nxt) = decode (nxt, end); + } + + point cur; + point nxt; + point end; + unicode_char val; +}; + +#endif \ No newline at end of file From 55ca037411de9f669da282c1c86203862e74b029 Mon Sep 17 00:00:00 2001 From: Nathan Jeffords Date: Sun, 27 Jan 2013 11:56:00 -0800 Subject: [PATCH 0530/1537] Created a MyGUI widget to present a page of formatted text. --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/bookpage.cpp | 1204 ++++++++++++++++++++++++ apps/openmw/mwgui/bookpage.hpp | 120 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 2 + 4 files changed, 1327 insertions(+), 1 deletion(-) create mode 100644 apps/openmw/mwgui/bookpage.cpp create mode 100644 apps/openmw/mwgui/bookpage.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4fdcb390e..fcd2c14500 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -31,7 +31,7 @@ add_openmw_dir (mwgui confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog spellcreationdialog enchantingdialog trainingwindow travelwindow imagebutton exposedwindow cursor spellicons - merchantrepair repair soulgemdialog companionwindow + merchantrepair repair soulgemdialog companionwindow bookpage ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp new file mode 100644 index 0000000000..4007dc1f19 --- /dev/null +++ b/apps/openmw/mwgui/bookpage.cpp @@ -0,0 +1,1204 @@ +#include "bookpage.hpp" + +#include "MyGUI_FontManager.h" +#include "MyGUI_RenderItem.h" +#include "MyGUI_RenderManager.h" +#include "MyGUI_TextureUtility.h" +#include "MyGUI_FactoryManager.h" + +#include + +#include + +namespace MWGui +{ + struct TypesetBook; + struct PageDisplay; + struct BookPage; +} + +using namespace MyGUI; +using namespace MWGui; + +static bool ucs_space (int code_point); +static bool ucs_line_break (int code_point); +static bool ucs_breaking_space (int code_point); + +struct IBookTypesetter::IStyle { virtual ~IStyle () {} }; + +struct MWGui::TypesetBook : ITypesetBook +{ + typedef std::vector content; + typedef std::list contents; + typedef utf8_stream::point utf8_point; + typedef std::pair range; + + struct style : IBookTypesetter::IStyle + { + IFont* Font; + Colour HotColour; + Colour ActiveColour; + Colour NormalColour; + interactive_id InteractiveId; + + bool match (IFont* tstFont, Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return (Font == tstFont) && + partal_match (tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId); + } + + bool match (char const * tstFont, Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return (Font->getResourceName () == tstFont) && + partal_match (tstHotColour, tstActiveColour, tstNormalColour, tstInteractiveId); + } + + bool partal_match (Colour tstHotColour, Colour tstActiveColour, Colour tstNormalColour, intptr_t tstInteractiveId) + { + return + (HotColour == tstHotColour ) && + (ActiveColour == tstActiveColour ) && + (NormalColour == tstNormalColour ) && + (InteractiveId == tstInteractiveId ) ; + } + }; + + typedef std::list