diff --git a/CMakeLists.txt b/CMakeLists.txt index 63c65381b..6b2867880 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,16 @@ option(USE_AUDIERE "use Audiere for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" OFF) option(USE_MPG123 "use mpg123 + libsndfile for sound" ON) +find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems") + # Location of morrowind data files -set(MORROWIND_DATA_FILES "data" - CACHE PATH "location of Morrowind data files") +if(DPKG_PROGRAM) + set(MORROWIND_DATA_FILES "/usr/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") + set(MORROWIND_RESOURCE_FILES "/usr/share/games/openmw/resources/" CACHE PATH "location of Morrowind data files") +else() + set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") + set(MORROWIND_RESOURCE_FILES "resources" CACHE PATH "location of Morrowind data files") +endif() if (WIN32) option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON) @@ -263,7 +270,7 @@ configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.win32 "${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY) else (WIN32) configure_file(${OpenMW_SOURCE_DIR}/files/plugins.cfg.linux - "${OpenMW_BINARY_DIR}/plugins.cfg" COPYONLY) + "${OpenMW_BINARY_DIR}/plugins.cfg") endif (WIN32) configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg @@ -309,6 +316,57 @@ set(CMAKE_CXX_FLAGS "-arch i386") endif (APPLE) + +if(DPKG_PROGRAM) + SET(CMAKE_INSTALL_PREFIX "/usr") + + if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.git") + exec_program("git" ${CMAKE_CURRENT_SOURCE_DIR} ARGS "describe" OUTPUT_VARIABLE GIT_VERSION ) + STRING(REGEX REPLACE "openmw-" "" VERSION_STRING "${GIT_VERSION}") + exec_program("git" ARGS "config --get user.name" OUTPUT_VARIABLE GIT_NAME ) + exec_program("git" ARGS "config --get user.email" OUTPUT_VARIABLE GIT_EMAIL) + set(PACKAGE_MAINTAINER "${GIT_NAME} <${GIT_EMAIL}>") + else() + #FIXME this should probably be read from some file like ${CMAKE_CURRENT_SOURCE_DIR}/VERSION or something that gets updated when changing version + set(VERSION_STRING "0.9.0") + set(PACKAGE_MAINTAINER "unknown") + endif() + + #Install global configuration files + INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + INSTALL(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "../etc/openmw/" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") + + #Install resources + INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "share/games/openmw/" FILE_PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT "Resources") + INSTALL(DIRECTORY DESTINATION "share/games/openmw/data/" COMPONENT "Resources") + + SET(CPACK_GENERATOR "DEB") + SET(CPACK_PACKAGE_NAME "openmw") + SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.com") + SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") + SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PACKAGE_MAINTAINER}") + SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A reimplementation of The Elder Scrolls III: Morrowind + OpenMW is a reimplementation of the Bethesda Game Studios game The Elder Scrolls III: Morrowind. + Data files from the original game is required to run it.") + SET(CPACK_DEBIAN_PACKAGE_NAME "openmw") + SET(CPACK_DEBIAN_PACKAGE_VERSION "${VERSION_STRING}") + SET(CPACK_PACKAGE_EXECUTABLES "openmw;OpenMW") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libogremain-1.7.1 (>= 1.7.1-1), libboost-filesystem1.42.0 (>= 1.42.0), libboost-program-options1.42.0 (>= 1.42.0), libboost-system1.42.0 (>= 1.42.0), libboost-thread1.42.0 (>= 1.42.0), libc6 (>= 2.11.2), libfreetype6 (>= 2.2.1), libgcc1 (>= 1:4.1.1), libmpg123-0 (>= 1.12.1), libois-1.2.0 (>= 1.2.0), libopenal1 (>= 1:1.12.854), libsndfile1 (>= 1.0.23), libstdc++6 (>= 4.4.5), libuuid1 (>= 2.17.2)") + + SET(CPACK_DEBIAN_PACKAGE_SECTION "Games") + + string(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_PACKAGE_NAME_LOWERCASE) + execute_process( + COMMAND ${DPKG_PROGRAM} --print-architecture + OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME_LOWERCASE}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") + + + include(CPack) +endif(DPKG_PROGRAM) + # Apps and tools add_subdirectory( apps/openmw ) diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 465e485e4..5d10b4fed 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -4,7 +4,8 @@ project(OpenMW) set(GAME main.cpp - engine.cpp) + engine.cpp + path.cpp) set(GAME_HEADER engine.hpp) source_group(game FILES ${GAME} ${GAME_HEADER}) @@ -242,3 +243,7 @@ if (APPLE) find_library(CARBON_FRAMEWORK Carbon) target_link_libraries(openmw ${CARBON_FRAMEWORK}) endif (APPLE) + +if(DPKG_PROGRAM) + INSTALL(TARGETS openmw RUNTIME DESTINATION games COMPONENT openmw) +endif() diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index fda8e8d78..3eaff2fe1 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -41,6 +41,7 @@ #include #include "mwgui/class.hpp" +#include "path.hpp" //using namespace ESM; @@ -245,6 +246,12 @@ void OMW::Engine::setDataDir (const boost::filesystem::path& dataDir) mDataDir = boost::filesystem::system_complete (dataDir); } +// Set resource dir +void OMW::Engine::setResourceDir (const boost::filesystem::path& parResDir) +{ + mResDir = boost::filesystem::system_complete(parResDir); +} + // Set start cell name (only interiors for now) void OMW::Engine::setCell (const std::string& cellName) @@ -300,16 +307,26 @@ void OMW::Engine::go() std::cout << "Data directory: " << mDataDir << "\n"; - const char* plugCfg = "plugins.cfg"; + std::string cfgDir = OMW::Path::getPath(OMW::Path::GLOBAL_CFG_PATH, "openmw", ""); + std::string cfgUserDir = OMW::Path::getPath(OMW::Path::USER_CFG_PATH, "openmw", ""); + std::string plugCfg = "plugins.cfg"; + std::string ogreCfg = "ogre.cfg"; + ogreCfg.insert(0, cfgUserDir); - mOgre.configure(!isFile("ogre.cfg"), plugCfg, false); + //A local plugins.cfg will be used if it exist, otherwise look in the default path + if(!isFile(plugCfg.c_str())) + { + plugCfg.insert(0, cfgDir); + } + + mOgre.configure(!isFile(ogreCfg.c_str()), cfgUserDir, plugCfg, false); addResourcesDirectory (mDataDir / "Meshes"); addResourcesDirectory (mDataDir / "Textures"); // This has to be added BEFORE MyGUI is initialized, as it needs // to find core.xml here. - addResourcesDirectory("resources/mygui/"); + addResourcesDirectory(mResDir / "mygui"); // Create the window mOgre.createWindow("OpenMW"); @@ -317,11 +334,10 @@ void OMW::Engine::go() loadBSA(); // Create the world - mEnvironment.mWorld = new MWWorld::World (mOgre, mDataDir, mMaster, mNewGame, mEnvironment); + mEnvironment.mWorld = new MWWorld::World (mOgre, mDataDir, mMaster, mResDir, mNewGame, mEnvironment); // Set up the GUI system - mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(), - mOgre.getScene()); + mGuiManager = new OEngine::GUI::MyGUIManager(mOgre.getWindow(), mOgre.getScene(), false, cfgDir); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index eeefbc65d..5b636398c 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -57,6 +57,7 @@ namespace OMW //int nFiles; boost::filesystem::path mDataDir; + boost::filesystem::path mResDir; OEngine::Render::OgreRenderer mOgre; std::string mCellName; std::string mMaster; @@ -107,6 +108,9 @@ namespace OMW /// Set data dir void setDataDir (const boost::filesystem::path& dataDir); + /// Set resource dir + void setResourceDir (const boost::filesystem::path& parResDir); + /// Set start cell name (only interiors for now) void setCell (const std::string& cellName); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 393228777..990e6b51c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -7,9 +7,10 @@ #include #include "engine.hpp" +#include "path.hpp" #if defined(_WIN32) && !defined(_CONSOLE) -#include +#include #include # if !defined(_DEBUG) @@ -42,6 +43,8 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) ("help", "print help message") ("data", bpo::value()->default_value ("data"), "set data directory") + ("resources", bpo::value()->default_value ("resources"), + "set resources directory") ("start", bpo::value()->default_value ("Beshara"), "set initial cell") ("master", bpo::value()->default_value ("Morrowind"), @@ -55,20 +58,23 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) bpo::variables_map variables; -#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE - std::string configFilePath(macBundlePath() + "/Contents/MacOS/openmw.cfg"); - std::ifstream configFile (configFilePath.c_str()); -#else - std::ifstream configFile ("openmw.cfg"); -#endif + std::string cfgFile = OMW::Path::getPath(OMW::Path::GLOBAL_CFG_PATH, "openmw", "openmw.cfg"); + std::cout << "Using global config file: " << cfgFile << std::endl; + std::ifstream globalConfigFile(cfgFile.c_str()); + + cfgFile = OMW::Path::getPath(OMW::Path::USER_CFG_PATH, "openmw", "openmw.cfg"); + std::cout << "Using user config file: " << cfgFile << std::endl; + std::ifstream userConfigFile(cfgFile.c_str()); bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv).options(desc).allow_unregistered().run(); bpo::store(valid_opts, variables); bpo::notify(variables); - if (configFile.is_open()) - bpo::store ( bpo::parse_config_file (configFile, desc), variables); + if (userConfigFile.is_open()) + bpo::store ( bpo::parse_config_file (userConfigFile, desc), variables); + if (globalConfigFile.is_open()) + bpo::store ( bpo::parse_config_file (globalConfigFile, desc), variables); if (variables.count ("help")) { @@ -77,6 +83,7 @@ bool parseOptions (int argc, char**argv, OMW::Engine& engine) } engine.setDataDir (variables["data"].as()); + engine.setResourceDir (variables["resources"].as()); engine.setCell (variables["start"].as()); engine.addMaster (variables["master"].as()); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index ed247cc80..bc933b918 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -16,7 +16,7 @@ #include "../mwmechanics/mechanicsmanager.hpp" #include -namespace +namespace { const Ogre::Radian kOgrePi (Ogre::Math::PI); const Ogre::Radian kOgrePiOverTwo (Ogre::Math::PI / Ogre::Real(2.0)); @@ -38,7 +38,7 @@ namespace MWClass //Ogre::SceneNode *chest; ESMS::LiveCellRef *ref = ptr.get(); - + //Store scenenodes by npc's name + bodypart [0] , npc's name + bodypart [1] //Ex. Fargothchest , Fargothneck @@ -58,7 +58,7 @@ namespace MWClass environment.mWorld->getStore().bodyParts.find(hairID)->model; MWRender::Rendering rendering (cellRender, ref->ref); - + //TODO: define consts for each bodypart e.g. chest, foot, wrist... and put the parts in the // right place @@ -69,7 +69,7 @@ namespace MWClass Ogre::Vector3 pos = Ogre::Vector3( 20, 20, 20); Ogre::Vector3 axis = Ogre::Vector3( 0, 0, 1); Ogre::Radian angle = Ogre::Radian(0); - + std::string addresses[6] = {"", "", "", "","", ""}; std::string addresses2[6] = {"", "", "", "", "", ""}; std::string upperleft[5] = {"", "", "", "", ""}; @@ -79,9 +79,9 @@ namespace MWClass int numbers = 0; int uppernumbers = 0; int neckNumbers = 0; - + if (bodyPart){ - + cellRender.insertMesh("meshes\\" + bodyPart->model, pos, axis, angle, npcName + "chest", addresses, numbers, true); //2 0 addresses2[numbers] = npcName + "chest"; addresses[numbers++] = npcName + "chest"; @@ -111,7 +111,7 @@ namespace MWClass Ogre::Vector3 pos2 = Ogre::Vector3( 0, .5, 75); std::string upperarmpath[2] = {npcName + "chest", npcName + "upper arm"}; - + if (groin){ cellRender.insertMesh("meshes\\" + groin->model, pos2, axis, kOgrePi, npcName + "groin", addresses, numbers); addresses2[numbers] = npcName + "groin"; @@ -121,7 +121,7 @@ namespace MWClass cellRender.insertMesh("tail\\" + tail->model, Ogre::Vector3(0 , 0, -76), axis, kOgrePi, npcName + "tail", addresses, numbers, "tail"); //std::cout << "TAIL\n"; } - + //addresses[1] = npcName + "groin"; if(upperleg){ cellRender.insertMesh ("meshes\\" + upperleg->model, Ogre::Vector3( 6, 0, -16), axis, kOgrePi, npcName + "upper leg", addresses, numbers); //-18 @@ -135,15 +135,15 @@ namespace MWClass cellRender.insertMesh ("meshes\\" + knee->model, Ogre::Vector3( 0, -1, -23), axis, Ogre::Radian(0), npcName + "knee", addresses, numbers); //cellRender.rotateMesh(Ogre::Vector3(0, 1, 0), Ogre::Radian (1), npcName + "upper arm"); cellRender.insertMesh ("meshes\\" + knee->model, Ogre::Vector3( 0, -1, -23), axis, Ogre::Radian(0), npcName + "knee2", addresses2, numbers); - + addresses2[numbers] = npcName + "knee2"; addresses[numbers++] = npcName + "knee"; } if(ankle){ - + cellRender.insertMesh ("meshes\\" + ankle->model, Ogre::Vector3( 0, 0, -20), axis, Ogre::Radian(0), npcName + "ankle", addresses, numbers); //-1 cellRender.insertMesh ("meshes\\" + ankle->model, Ogre::Vector3( 0,0, -20), axis, Ogre::Radian(0), npcName + "ankle2", addresses2, numbers); //-1 - + addresses2[numbers] = npcName + "ankle2"; addresses[numbers++] = npcName + "ankle"; } @@ -163,7 +163,7 @@ namespace MWClass //cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), addresses, numbers); } if(feet){ - + cellRender.insertMesh ("foot\\" + feet->model, Ogre::Vector3( 7, 4, -16), axis, kOgrePi, npcName + "foot", addresses, numbers); //9, 0, -14 cellRender.insertMesh ("foot\\" + feet->model, Ogre::Vector3( 7, 4, -16), axis, kOgrePi, npcName + "foot2", addresses2, numbers); @@ -171,8 +171,8 @@ namespace MWClass addresses[numbers++] = npcName + "foot"; //cellRender.scaleMesh(Ogre::Vector3(1, -1, 1), addresses, numbers); } - - + + if (arm){ //010 cellRender.insertMesh("meshes\\" + arm->model, Ogre::Vector3(-12.5, 0, 104), Ogre::Vector3(0, 1, 0), -kOgrePiOverTwo, npcName + "upper arm", upperleft, uppernumbers); //1, 0,.75 @@ -209,7 +209,7 @@ namespace MWClass upperleft[uppernumbers] = npcName + "wrist"; upperright[uppernumbers++] = npcName + "wrist2"; } - + if(hand) { @@ -218,7 +218,7 @@ namespace MWClass //std::cout << "WE FOUND HANDS\n"; std::string pass; if(hand->model.compare("b\\B_N_Dark Elf_F_Hands.1st.NIF")==0 && bodyRaceID.compare("b_n_dark elf_m_") == 0) - pass = "b\\B_N_Dark Elf_M_Hands.1st.NIF"; + pass = "b\\B_N_Dark Elf_M_Hands.1st.NIF"; else pass = hand->model; cellRender.insertMesh("meshes\\" + pass, Ogre::Vector3(42, 1, -110), Ogre::Vector3(0, 0, 0), kOgrePi, npcName + "hand", upperleft, uppernumbers,false); //0, 100, -100 0,0,120 @@ -257,7 +257,7 @@ namespace MWClass neckandup[neckNumbers++] = npcName + "head"; cellRender.insertMesh (hairModel, Ogre::Vector3( 0, -1, 0), axis, Ogre::Radian(0), npcName + "hair", neckandup, neckNumbers); ref->mData.setHandle (rendering.end (ref->mData.isEnabled())); - + } void Npc::enable (const MWWorld::Ptr& ptr, MWWorld::Environment& environment) const @@ -311,7 +311,6 @@ namespace MWClass { if (!ptr.getRefData().getNpcStats().get()) { - // xxx boost::shared_ptr stats ( new MWMechanics::NpcStats); @@ -363,6 +362,80 @@ namespace MWClass return ref->base->script; } + void Npc::setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const + { + MWMechanics::NpcStats& stats = getNpcStats (ptr); + + switch (stance) + { + case Run: + + stats.mForceRun = force; + break; + + case Sneak: + + stats.mForceSneak = force; + break; + + case Combat: + + throw std::runtime_error ("combat stance not enforcable for NPCs"); + } + } + + void Npc::setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const + { + MWMechanics::NpcStats& stats = getNpcStats (ptr); + + switch (stance) + { + case Run: + + throw std::runtime_error ("run stance not manually setable for NPCs"); + + case Sneak: + + stats.mSneak = set; + break; + + case Combat: + + stats.mCombat = set; + break; + } + } + + bool Npc::getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce) const + { + MWMechanics::NpcStats& stats = getNpcStats (ptr); + + switch (stance) + { + case Run: + + return ignoreForce ? false : stats.mForceRun; + + case Sneak: + + if (!ignoreForce && stats.mForceSneak) + return true; + + return stats.mSneak; + + case Combat: + + return stats.mCombat; + } + + return false; + } + + float Npc::getSpeed (const MWWorld::Ptr& ptr) const + { + return getStance (ptr, Run) ? 600 : 300; // TODO calculate these values from stats + } + void Npc::registerSelf() { boost::shared_ptr instance (new Npc); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index e54c35ad8..1d9d90c4d 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -8,7 +8,7 @@ namespace MWClass class Npc : public MWWorld::Class { public: - + virtual std::string getId (const MWWorld::Ptr& ptr) const; ///< Return ID of \a ptr @@ -43,6 +43,19 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr + virtual void setForceStance (const MWWorld::Ptr& ptr, Stance stance, bool force) const; + ///< Force or unforce a stance. + + virtual void setStance (const MWWorld::Ptr& ptr, Stance stance, bool set) const; + ///< Set or unset a stance. + + virtual bool getStance (const MWWorld::Ptr& ptr, Stance stance, bool ignoreForce = false) + const; + ////< Check if a stance is active or not. + + virtual float getSpeed (const MWWorld::Ptr& ptr) const; + ///< Return movement speed. + static void registerSelf(); }; } diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 31623fb58..1cc6eca2a 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -48,6 +48,26 @@ namespace MWInput A_Activate, + A_Use, //Use weapon, spell, etc. + A_Jump, + A_AutoMove, //Toggle Auto-move forward + A_Rest, //Rest + A_Journal, //Journal + A_Weapon, //Draw/Sheath weapon + A_Spell, //Ready/Unready Casting + A_AlwaysRun, //Toggle Always Run + A_CycleSpellLeft, //cycling through spells + A_CycleSpellRight, + A_CycleWeaponLeft,//Cycling through weapons + A_CycleWeaponRight, + A_ToggleSneak, //Toggles Sneak, add Push-Sneak later + A_ToggleWalk, //Toggle Walking/Running + + A_QuickSave, + A_QuickLoad, + A_QuickMenu, + A_GameMenu, + A_LAST // Marker for the last item }; @@ -68,11 +88,14 @@ namespace MWInput // Count screenshots. int shotCount; + + /* InputImpl Methods */ + // Write screenshot to file. void screenshot() { - // Find the first unused filename. - // + + // Find the first unused filename with a do-while char buf[50]; do { @@ -82,8 +105,8 @@ namespace MWInput ogre.screenshot(buf); } - // Called when the user presses the button to toggle the inventory - // screen. + + /* toggleInventory() is called when the user presses the button to toggle the inventory screen. */ void toggleInventory() { using namespace MWGui; @@ -118,6 +141,21 @@ namespace MWInput mEngine.activate(); } + void toggleAutoMove() + { + if (player.getAutoMove() == false) + { + player.setAutoMove(true); + } else { + player.setAutoMove(false); + } + } + + void toggleWalking() + { + player.setisWalking(true); + } + // Exit program now button (which is disabled in GUI mode) void exitNow() { @@ -159,7 +197,10 @@ namespace MWInput "Toggle console"); disp->funcs.bind(A_Activate, boost::bind(&InputImpl::activate, this), "Activate"); - + disp->funcs.bind(A_AutoMove, boost::bind(&InputImpl::toggleAutoMove, this), + "Auto Move"); + disp->funcs.bind(A_ToggleWalk, boost::bind(&InputImpl::toggleWalking, this), + "Toggle Walk/Run"); // Add the exit listener ogre.getRoot()->addFrameListener(&exit); @@ -195,6 +236,7 @@ namespace MWInput **********************************/ // Key bindings for keypress events + // NOTE: These keys do not require constant polling - use in conjuction with variables in loops. disp->bind(A_Quit, KC_Q); disp->bind(A_Quit, KC_ESCAPE); @@ -202,8 +244,12 @@ namespace MWInput disp->bind(A_Inventory, KC_I); disp->bind(A_Console, KC_F1); disp->bind(A_Activate, KC_SPACE); + disp->bind(A_AutoMove, KC_Z); + disp->bind(A_ToggleSneak, KC_X); + disp->bind(A_ToggleWalk, KC_C); // Key bindings for polled keys + // NOTE: These keys are constantly being polled. Only add keys that must be checked each frame. // Arrow keys poller.bind(A_MoveLeft, KC_LEFT); @@ -222,7 +268,7 @@ namespace MWInput poller.bind(A_MoveDown, KC_LCONTROL); } - // Used to check for movement keys + //NOTE: Used to check for movement keys bool frameStarted(const Ogre::FrameEvent &evt) { // Tell OIS to handle all input events @@ -239,13 +285,39 @@ namespace MWInput // Disable movement in Gui mode if(windows.isGuiMode()) return true; - float speed = 300 * evt.timeSinceLastFrame; + float speed = 300 * evt.timeSinceLastFrame; //placeholder player speed? + //float TESTwalkSpeed = 100 * evt.timeSinceLastFrame; //How about another? + float moveX = 0, moveY = 0, moveZ = 0; - if(poller.isDown(A_MoveLeft)) moveX -= speed; - if(poller.isDown(A_MoveRight)) moveX += speed; - if(poller.isDown(A_MoveForward)) moveZ -= speed; - if(poller.isDown(A_MoveBackward)) moveZ += speed; + //execute Automove - condition checked in function + player.executeAutoMove((float)evt.timeSinceLastFrame); //or since last frame? + + //Poll and execute movement keys - will disable automove if pressed. + if(poller.isDown(A_MoveLeft)) + { + player.setAutoMove(false); + moveX -= speed; + } + + if(poller.isDown(A_MoveRight)) + { + player.setAutoMove(false); + moveX += speed; + } + + if(poller.isDown(A_MoveForward)) + { + player.setAutoMove(false); + moveZ -= speed; + } + + if(poller.isDown(A_MoveBackward)) + { + player.setAutoMove(false); + moveZ += speed; + } + // TODO: These should be enabled for floating modes (like // swimming and levitation) and disabled for everything else. @@ -288,6 +360,7 @@ namespace MWInput } }; + /***CONSTRUCTOR***/ MWInputManager::MWInputManager(OEngine::Render::OgreRenderer &ogre, MWWorld::Player &player, MWGui::WindowManager &windows, @@ -297,6 +370,7 @@ namespace MWInput impl = new InputImpl(ogre,player,windows,debug, engine); } + /***DESTRUCTOR***/ MWInputManager::~MWInputManager() { delete impl; diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index b5ca93749..fa0e46b1a 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -18,6 +18,13 @@ namespace MWMechanics std::map mFactionRank; Stat mSkill[27]; + + bool mForceRun; + bool mForceSneak; + bool mSneak; + bool mCombat; + + NpcStats() : mForceRun (false), mForceSneak (false), mSneak (false), mCombat (false) {} }; } diff --git a/apps/openmw/mwrender/mwscene.cpp b/apps/openmw/mwrender/mwscene.cpp index 5fff2c295..aacda6be5 100644 --- a/apps/openmw/mwrender/mwscene.cpp +++ b/apps/openmw/mwrender/mwscene.cpp @@ -97,3 +97,13 @@ std::pair MWScene::getFacedHandle (MWWorld::World& world) return std::pair(handle, distance); } + +void MWScene::doPhysics (float duration, MWWorld::World& world) +{ + +} + +void MWScene::setMovement (const std::vector& actors) +{ + +} diff --git a/apps/openmw/mwrender/mwscene.hpp b/apps/openmw/mwrender/mwscene.hpp index b4c8357cf..9c698c95b 100644 --- a/apps/openmw/mwrender/mwscene.hpp +++ b/apps/openmw/mwrender/mwscene.hpp @@ -54,6 +54,13 @@ namespace MWRender /// name is empty and distance = -1 if there is no object which /// can be faced std::pair getFacedHandle (MWWorld::World& world); + + /// Run physics simulation and modify \a world accordingly. + void doPhysics (float duration, MWWorld::World& world); + + /// Inform phyiscs system about desired velocity vectors for actors + /// (in Morrowind coordinates). + void setMovement (const std::vector& actors); }; } diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index d86ef35fb..95601d043 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -19,7 +19,8 @@ namespace MWRender public: CaelumManager (Ogre::RenderWindow* pRenderWindow, - Ogre::Camera* pCamera); + Ogre::Camera* pCamera, + const boost::filesystem::path& resDir); virtual ~CaelumManager (); virtual void enable() {} @@ -44,7 +45,8 @@ namespace MWRender }; CaelumManager::CaelumManager (Ogre::RenderWindow* pRenderWindow, - Ogre::Camera* pCamera) + Ogre::Camera* pCamera, + const boost::filesystem::path& resDir) : mpCaelumSystem (NULL) { using namespace Ogre; @@ -55,7 +57,7 @@ namespace MWRender // Load the Caelum resources // - ResourceGroupManager::getSingleton().addResourceLocation("resources/caelum", "FileSystem", "Caelum"); + ResourceGroupManager::getSingleton().addResourceLocation((resDir / "caelum").string(), "FileSystem", "Caelum"); ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // Load the Caelum resources @@ -89,13 +91,14 @@ namespace MWRender /// \return NULL on failure. /// SkyManager* SkyManager::create (Ogre::RenderWindow* pRenderWindow, - Ogre::Camera* pCamera) + Ogre::Camera* pCamera, + const boost::filesystem::path& resDir) { SkyManager* pSkyManager = NULL; try { - pSkyManager = new CaelumManager(pRenderWindow, pCamera); + pSkyManager = new CaelumManager(pRenderWindow, pCamera, resDir); } catch (Ogre::Exception& e) { diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 1aae5126e..446ed3f1c 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -1,6 +1,8 @@ #ifndef _GAME_RENDER_SKY_H #define _GAME_RENDER_SKY_H +#include + namespace Ogre { class RenderWindow; @@ -16,7 +18,8 @@ namespace MWRender { public: static SkyManager* create (Ogre::RenderWindow* pRenderWindow, - Ogre::Camera* pCamera); + Ogre::Camera* pCamera, + const boost::filesystem::path& resDir); virtual ~SkyManager() {} virtual void enable() = 0; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 1e9f25bbd..837b3b294 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -92,6 +92,26 @@ namespace MWWorld return ""; } + void Class::setForceStance (const Ptr& ptr, Stance stance, bool force) const + { + throw std::runtime_error ("stance not supported by class"); + } + + void Class::setStance (const Ptr& ptr, Stance stance, bool set) const + { + throw std::runtime_error ("stance not supported by class"); + } + + bool Class::getStance (const Ptr& ptr, Stance stance, bool ignoreForce) const + { + return false; + } + + float Class::getSpeed (const Ptr& ptr) const + { + return 0; + } + 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 5153d7468..51c727aad 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -41,6 +41,12 @@ namespace MWWorld public: + /// NPC-stances. + enum Stance + { + Run, Sneak, Combat + }; + virtual ~Class(); virtual std::string getId (const Ptr& ptr) const; @@ -108,6 +114,18 @@ namespace MWWorld ///< Return name of the script attached to ptr (default implementation: return an empty /// string). + virtual void setForceStance (const Ptr& ptr, Stance stance, bool force) const; + ///< Force or unforce a stance. + + virtual void setStance (const Ptr& ptr, Stance stance, bool set) const; + ///< Set or unset a stance. + + virtual bool getStance (const Ptr& ptr, Stance stance, bool ignoreForce = false) const; + ////< Check if a stance is active or not. + + virtual float getSpeed (const Ptr& ptr) const; + ///< Return movement speed. + static const Class& get (const std::string& key); ///< If there is no class for this \a key, an exception is thrown. diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index cc7abccac..b0805269d 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -16,6 +16,8 @@ namespace MWWorld mRace = player->race; mPlayer.ref.pos.pos[0] = mPlayer.ref.pos.pos[1] = mPlayer.ref.pos.pos[2] = 0; mClass = new ESM::Class (*world.getStore().classes.find (player->cls)); + mAutoMove = false; + misWalking = false; } Player::~Player() @@ -61,4 +63,5 @@ namespace MWWorld delete mClass; mClass = new_class; } + } diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 997282ca6..5174c2d33 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -31,6 +31,9 @@ namespace MWWorld ESM::Class *mClass; bool mCollisionMode; + bool mAutoMove; + bool misWalking;//Testing... + public: Player(MWRender::Player *renderer, const ESM::NPC *player, MWWorld::World& world); @@ -108,6 +111,39 @@ namespace MWWorld { mCollisionMode = !mCollisionMode; } - }; + + bool getAutoMove() + { + return mAutoMove; + } + + void setAutoMove(bool setMe) + { + mAutoMove = setMe; + } + +//NOTE: we don't have speed being calculated yet, so for now this function only requires a frame duration. +/// float value representing time since last call + void executeAutoMove(float duration) + { + float X_Val = 0.0f; + float Y_Val = 0.0f; + float Z_Val = 300.0f * duration * -1.0f; + if (mAutoMove == true) + { + moveRel(X_Val, Y_Val, Z_Val); + } + } + + bool getisWalking() + { + return misWalking; + } + + void setisWalking(bool setMe) + { + misWalking = setMe; + } + }; } #endif diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index 8dfc8c966..44bfa9112 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -316,7 +316,7 @@ namespace MWWorld } World::World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir, - const std::string& master, bool newGame, Environment& environment) + const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment) : mSkyManager (0), mScene (renderer), mPlayer (0), mCurrentCell (0), mGlobalVariables (0), mSky (false), mCellChanged (false), mEnvironment (environment) { @@ -341,7 +341,7 @@ namespace MWWorld } mSkyManager = - MWRender::SkyManager::create(renderer.getWindow(), mScene.getCamera()); + MWRender::SkyManager::create(renderer.getWindow(), mScene.getCamera(), resDir); } World::~World() diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 4e9e32ecc..ce66a63d7 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -89,8 +89,8 @@ namespace MWWorld public: - World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& master, - const std::string& dataDir, bool newGame, Environment& environment); + World (OEngine::Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir, + const std::string& master, const boost::filesystem::path& resDir, bool newGame, Environment& environment); ~World(); diff --git a/apps/openmw/path.cpp b/apps/openmw/path.cpp new file mode 100644 index 000000000..9de8158af --- /dev/null +++ b/apps/openmw/path.cpp @@ -0,0 +1,56 @@ +#include "path.hpp" + +#include + +#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX +#include //getenv +#endif + + +std::string OMW::Path::getPath(PathTypeEnum parType, const std::string parApp, const std::string parFile) +{ + std::string theBasePath; + if(parType == GLOBAL_CFG_PATH) + { +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + theBasePath = macBundlePath() + "/Contents/MacOS/"; //FIXME do we have global/local with OSX? +#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX + theBasePath = "/etc/"+parApp+"/"; +#else + theBasePath = ""; +#endif + + } + else + { +#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE + theBasePath = macBundlePath() + "/Contents/MacOS/"; //FIXME do we have global/local with OSX? +#elif OGRE_PLATFORM == OGRE_PLATFORM_LINUX + const char* theDir; + if ((theDir = getenv("OPENMW_HOME")) != NULL) + { + theBasePath = std::string(theDir)+"/"; + } + else + { + if ((theDir = getenv("XDG_CONFIG_HOME"))) + { + theBasePath = std::string(theDir)+"/"+parApp+"/"; + } + else + { + if ((theDir = getenv("HOME")) == NULL) + return parFile; + theBasePath = std::string(theDir)+"/.config/"+parApp+"/"; + } + } + boost::filesystem::create_directories(boost::filesystem::path(theBasePath)); +#else + theBasePath = ""; +#endif + } + + theBasePath.append(parFile); + return theBasePath; +} + diff --git a/apps/openmw/path.hpp b/apps/openmw/path.hpp new file mode 100644 index 000000000..719e45435 --- /dev/null +++ b/apps/openmw/path.hpp @@ -0,0 +1,21 @@ +#ifndef PATH__HPP +#define PATH__HPP + +#include +#include + +namespace OMW +{ + class Path + { + public: + enum PathTypeEnum + { + USER_CFG_PATH, + GLOBAL_CFG_PATH + }; + + static std::string getPath(PathTypeEnum parType, const std::string parApp, const std::string parFile); + }; +} +#endif diff --git a/cmake/FindOGRE.cmake b/cmake/FindOGRE.cmake index 5554d7d08..eebb20338 100644 --- a/cmake/FindOGRE.cmake +++ b/cmake/FindOGRE.cmake @@ -69,6 +69,14 @@ SET(OGRE_INCLUDE_DIR ${OGRE_INCLUDE_DIR} CACHE PATH "") SET(OGRE_LIBRARIES ${OGRE_LIBRARIES} CACHE STRING "") SET(OGRE_LIB_DIR ${OGRE_LIB_DIR} CACHE PATH "") +if(OGRE_LIB_DIR) + CMAKE_POLICY(SET CMP0009 NEW) + FILE(GLOB_RECURSE OGRE_PLUGINS "${OGRE_LIB_DIR}/Plugin_*.so") + FOREACH (OGRE_PLUGINS_FILE ${OGRE_PLUGINS}) + STRING(REGEX REPLACE "/[^/]*$" "" OGRE_PLUGIN_DIR ${OGRE_PLUGINS_FILE}) + ENDFOREACH(OGRE_PLUGINS_FILE) +endif() + IF (OGRE_INCLUDE_DIR AND OGRE_LIBRARIES) SET(OGRE_FOUND TRUE) ENDIF (OGRE_INCLUDE_DIR AND OGRE_LIBRARIES) diff --git a/files/openmw.cfg b/files/openmw.cfg index e0690803f..f5322ae8c 100644 --- a/files/openmw.cfg +++ b/files/openmw.cfg @@ -1,2 +1,3 @@ data=${MORROWIND_DATA_FILES} +resources=${MORROWIND_RESOURCE_FILES} diff --git a/files/plugins.cfg.linux b/files/plugins.cfg.linux index 57ec54e1a..b6e104351 100644 --- a/files/plugins.cfg.linux +++ b/files/plugins.cfg.linux @@ -1,7 +1,7 @@ # Defines plugins to load # Define plugin folder -PluginFolder=/usr/local/lib/OGRE/ +PluginFolder=${OGRE_PLUGIN_DIR} # Define plugins Plugin=RenderSystem_GL