diff --git a/CMakeLists.txt b/CMakeLists.txt index e01b3d26b..614a840c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 17) +set (OPENMW_VERSION_MINOR 18) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -513,6 +513,7 @@ if (WIN32) 4309 # Variable overflow, trying to store 128 in a signed char for example 4355 # Using 'this' in member initialization list 4701 # Potentially uninitialized local variable used + 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt ) foreach(d ${WARNINGS_DISABLE}) @@ -524,6 +525,7 @@ if (WIN32) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif (BUILD_LAUNCHER) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) + set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) endif(MSVC) # Same for MinGW @@ -631,7 +633,7 @@ if (APPLE) include(CPack) endif (APPLE) -if (NOT WIN32 AND NOT DPKG_PROGRAM) +if (NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) ## Non Debian based Linux building # paths set(BINDIR "${CMAKE_INSTALL_PREFIX}/usr/bin" CACHE PATH "Where to install binaries") @@ -662,4 +664,4 @@ if (NOT WIN32 AND NOT DPKG_PROGRAM) # Install resources INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${DATADIR}" ) INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${DATADIR}/resources" ) -endif(NOT WIN32 AND NOT DPKG_PROGRAM) +endif(NOT WIN32 AND NOT DPKG_PROGRAM AND NOT APPLE) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 64816fae5..d32a3b045 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -189,73 +189,8 @@ void DataFilesPage::setupConfig() } -bool DataFilesPage::setupDataFiles() +void DataFilesPage::addDataFiles(Files::Collections &fileCollections, const QString &encoding) { - // We use the Configuration Manager to retrieve the configuration values - boost::program_options::variables_map variables; - boost::program_options::options_description desc; - - desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) - ("data-local", boost::program_options::value()->default_value("")) - ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) - ("encoding", boost::program_options::value()->default_value("win1252")); - - mCfgMgr.readConfiguration(variables, desc); - - // Put the paths in a boost::filesystem vector to use with Files::Collections - mDataDirs = Files::PathContainer(variables["data"].as()); - - std::string local = variables["data-local"].as(); - if (!local.empty()) { - mDataLocal.push_back(Files::PathContainer::value_type(local)); - } - - if (mDataDirs.size()>1) - mDataDirs.resize (1); - - mCfgMgr.processPaths(mDataDirs); - - while (mDataDirs.empty()) { - QMessageBox msgBox; - msgBox.setWindowTitle("Error detecting Morrowind installation"); - msgBox.setIcon(QMessageBox::Warning); - msgBox.setStandardButtons(QMessageBox::Cancel); - msgBox.setText(tr("
Could not find the Data Files location

\ - The directory containing the data files was not found.

\ - Press \"Browse...\" to specify the location manually.
")); - - QAbstractButton *dirSelectButton = - msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); - - msgBox.exec(); - - if (msgBox.clickedButton() == dirSelectButton) { - - // Show a custom dir selection dialog which only accepts valid dirs - QString selectedDir = FileDialog::getExistingDirectory( - this, tr("Select Data Files Directory"), - QDir::currentPath(), - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); - - // Add the user selected data directory - if (!selectedDir.isEmpty()) { - mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); - mCfgMgr.processPaths(mDataDirs); - } else { - // Cancel from within the dir selection dialog - return false; - } - - } else { - // Cancel - return false; - } - } - - // Create a file collection for the data dirs - Files::Collections fileCollections(mDataDirs, !variables["fs-strict"].as()); - // First we add all the master files const Files::MultiDirCollection &esm = fileCollections.getCollection(".esm"); unsigned int i = 0; // Row number @@ -283,7 +218,7 @@ bool DataFilesPage::setupDataFiles() ESMReader fileReader; QStringList availableMasters; // Will contain all found masters - fileReader.setEncoding(variables["encoding"].as()); + fileReader.setEncoding(encoding.toStdString()); fileReader.open(iter->second.string()); // First we fill the availableMasters and the mMastersWidget @@ -350,10 +285,86 @@ bool DataFilesPage::setupDataFiles() } catch(std::runtime_error &e) { // An error occurred while reading the .esp + std::cerr << "Error reading .esp: " << e.what() << std::endl; continue; } } + +} + + +bool DataFilesPage::setupDataFiles() +{ + // We use the Configuration Manager to retrieve the configuration values + boost::program_options::variables_map variables; + boost::program_options::options_description desc; + + desc.add_options() + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data-local", boost::program_options::value()->default_value("")) + ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) + ("encoding", boost::program_options::value()->default_value("win1252")); + + mCfgMgr.readConfiguration(variables, desc); + + // Put the paths in a boost::filesystem vector to use with Files::Collections + mDataDirs = Files::PathContainer(variables["data"].as()); + + std::string local = variables["data-local"].as(); + if (!local.empty()) { + mDataLocal.push_back(Files::PathContainer::value_type(local)); + } + + mCfgMgr.processPaths(mDataDirs); + mCfgMgr.processPaths(mDataLocal); + + while (mDataDirs.empty()) { + QMessageBox msgBox; + msgBox.setWindowTitle("Error detecting Morrowind installation"); + msgBox.setIcon(QMessageBox::Warning); + msgBox.setStandardButtons(QMessageBox::Cancel); + msgBox.setText(tr("
Could not find the Data Files location

\ + The directory containing the data files was not found.

\ + Press \"Browse...\" to specify the location manually.
")); + + QAbstractButton *dirSelectButton = + msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole); + + msgBox.exec(); + + if (msgBox.clickedButton() == dirSelectButton) { + + // Show a custom dir selection dialog which only accepts valid dirs + QString selectedDir = FileDialog::getExistingDirectory( + this, tr("Select Data Files Directory"), + QDir::currentPath(), + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + // Add the user selected data directory + if (!selectedDir.isEmpty()) { + mDataDirs.push_back(Files::PathContainer::value_type(selectedDir.toStdString())); + mCfgMgr.processPaths(mDataDirs); + } else { + // Cancel from within the dir selection dialog + return false; + } + + } else { + // Cancel + return false; + } + } + + // Add the plugins in the data directories + Files::Collections dataCollections(mDataDirs, !variables["fs-strict"].as()); + Files::Collections dataLocalCollections(mDataLocal, !variables["fs-strict"].as()); + + addDataFiles(dataCollections, QString::fromStdString(variables["encoding"].as())); + addDataFiles(dataLocalCollections, QString::fromStdString(variables["encoding"].as())); + + mDataFilesModel->sort(0); + readConfig(); return true; } @@ -1139,11 +1150,13 @@ void DataFilesPage::writeConfig(QString profile) path = QString::fromStdString(it->string()); path.remove(QChar('\"')); + QDir dir(path); + // Make sure the string is quoted when it contains spaces if (path.contains(" ")) { - gameConfig << "data=\"" << path << "\"" << endl; + gameConfig << "data=\"" << dir.absolutePath() << "\"" << endl; } else { - gameConfig << "data=" << path << endl; + gameConfig << "data=" << dir.absolutePath() << endl; } } @@ -1152,10 +1165,12 @@ void DataFilesPage::writeConfig(QString profile) path = QString::fromStdString(mDataLocal.front().string()); path.remove(QChar('\"')); + QDir dir(path); + if (path.contains(" ")) { - gameConfig << "data-local=\"" << path << "\"" << endl; + gameConfig << "data-local=\"" << dir.absolutePath() << "\"" << endl; } else { - gameConfig << "data-local=" << path << endl; + gameConfig << "data-local=" << dir.absolutePath() << endl; } } diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 5078f6428..83b318677 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -89,6 +89,7 @@ private: const QStringList checkedPlugins(); const QStringList selectedMasters(); + void addDataFiles(Files::Collections &fileCollections, const QString &encoding); void addPlugins(const QModelIndex &index); void removePlugins(const QModelIndex &index); void uncheckPlugins(); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2bb2c0717..66844b280 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender renderingmanager debugging sky player animation npcanimation creatureanimation actors objects renderinginterface localmap occlusionquery terrain terrainmaterial water shadows - compositors characterpreview externalrendering + compositors characterpreview externalrendering globalmap ) add_openmw_dir (mwinput @@ -29,7 +29,7 @@ add_openmw_dir (mwgui map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list formatting inventorywindow container hud countdialog tradewindow settingswindow confirmationdialog alchemywindow referenceinterface spellwindow mainmenu quickkeysmenu - itemselection spellbuyingwindow loadingscreen + itemselection spellbuyingwindow loadingscreen levelupdialog waitdialog ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7e65bcdec..d1aff6d0f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -299,6 +299,7 @@ void OMW::Engine::go() mOgre->configure( mCfgMgr.getLogPath().string(), renderSystem, + Settings::Manager::getString("opengl rtt mode", "Video"), false); // This has to be added BEFORE MyGUI is initialized, as it needs @@ -306,6 +307,8 @@ void OMW::Engine::go() //addResourcesDirectory(mResDir); + addResourcesDirectory(mCfgMgr.getCachePath ().string()); + addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "gbuffer"); @@ -366,6 +369,7 @@ void OMW::Engine::go() pos.pos[2] = 0; mEnvironment.getWorld()->renderPlayer(); + mEnvironment.getWorld()->renderGlobalMap(); if (const ESM::Cell *exterior = MWBase::Environment::get().getWorld()->getExterior (mCellName)) { diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 58fe180e9..429163136 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -118,7 +118,7 @@ namespace MWBase /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::Stat& value) = 0; virtual void setValue (int parSkill, const MWMechanics::Stat& value) = 0; - virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value) = 0; + virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value) = 0; virtual void setValue (const std::string& id, const std::string& value) = 0; virtual void setValue (const std::string& id, int value) = 0; @@ -189,6 +189,8 @@ namespace MWBase virtual void allowMouse() = 0; virtual void notifyInputActionBound() = 0; + virtual void addVisitedLocation(const std::string& name, int x, int y) = 0; + virtual void removeDialog(OEngine::GUI::Layout* dialog) = 0; ///< Hides dialog and schedules dialog to be deleted. @@ -219,6 +221,11 @@ namespace MWBase virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total) = 0; virtual void loadingDone() = 0; + + virtual void enableRest() = 0; + virtual bool getRestEnabled() = 0; + + virtual bool getPlayerSleeping() = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a83d6906f..ee474f357 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -160,6 +160,9 @@ namespace MWBase virtual void setDay (int day) = 0; ///< Set in-game time day. + virtual int getDay() = 0; + virtual int getMonth() = 0; + virtual MWWorld::TimeStamp getTimeStamp() const = 0; ///< Return current in-game time stamp. @@ -204,6 +207,9 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 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). + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const = 0; ///< Convert cell numbers to position. @@ -218,7 +224,7 @@ namespace MWBase virtual bool toggleCollisionMode() = 0; ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. - ///< \return Resulting mode + /// \return Resulting mode virtual bool toggleRenderMode (RenderMode mode) = 0; ///< Toggle a render mode. @@ -276,8 +282,16 @@ namespace MWBase virtual void togglePlayerLooking(bool enable) = 0; virtual void renderPlayer() = 0; + virtual void renderGlobalMap() = 0; virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; + + virtual int canRest() = 0; + ///< check if the player is allowed to rest \n + /// 0 - yes \n + /// 1 - only waiting \n + /// 2 - player is underwater \n + /// 3 - enemies are nearby (not implemented) }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index af849ca90..e7ec1d794 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -141,6 +141,7 @@ namespace MWClass assert(ref->base != NULL); std::string headID = ref->base->mHead; + int end = headID.find_last_of("head_") - 4; std::string bodyRaceID = headID.substr(0, end); @@ -153,6 +154,7 @@ namespace MWClass model = "meshes\\base_animkna.nif"; } return model; + } std::string Npc::getName (const MWWorld::Ptr& ptr) const @@ -297,7 +299,7 @@ namespace MWClass { Ogre::Vector3 vector (0, 0, 0); - vector.x = - getMovementSettings (ptr).mLeftRight * 127; + vector.x = getMovementSettings (ptr).mLeftRight * 127; vector.y = getMovementSettings (ptr).mForwardBackward * 127; vector.z = getMovementSettings(ptr).mUpDown * 127; diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 7f8e5c90e..e5bcdbaf8 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -151,7 +151,7 @@ void CharacterCreation::setValue (const std::string& id, const MWMechanics::Stat } } -void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +void CharacterCreation::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { if (mReviewDialog) { @@ -294,17 +294,17 @@ void CharacterCreation::spawnDialog(const char id) } } -void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) +void CharacterCreation::setPlayerHealth (const MWMechanics::DynamicStat& value) { mPlayerHealth = value; } -void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) +void CharacterCreation::setPlayerMagicka (const MWMechanics::DynamicStat& value) { mPlayerMagicka = value; } -void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) +void CharacterCreation::setPlayerFatigue (const MWMechanics::DynamicStat& value) { mPlayerFatigue = value; } diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index d65763d0c..28ced2e70 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -35,14 +35,14 @@ namespace MWGui //Show a dialog void spawnDialog(const char id); - void setPlayerHealth (const MWMechanics::DynamicStat& value); + void setPlayerHealth (const MWMechanics::DynamicStat& value); - void setPlayerMagicka (const MWMechanics::DynamicStat& value); + void setPlayerMagicka (const MWMechanics::DynamicStat& value); - void setPlayerFatigue (const MWMechanics::DynamicStat& value); + void setPlayerFatigue (const MWMechanics::DynamicStat& value); void setValue (const std::string& id, const MWMechanics::Stat& value); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); @@ -65,9 +65,9 @@ namespace MWGui std::string mPlayerRaceId; std::string mPlayerBirthSignId; ESM::Class mPlayerClass; - MWMechanics::DynamicStat mPlayerHealth; - MWMechanics::DynamicStat mPlayerMagicka; - MWMechanics::DynamicStat mPlayerFatigue; + MWMechanics::DynamicStat mPlayerHealth; + MWMechanics::DynamicStat mPlayerMagicka; + MWMechanics::DynamicStat mPlayerFatigue; //Class generation vars unsigned mGenerateClassStep; // Keeps track of current step in Generate Class dialog diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index d898efad1..ed0e59226 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -161,7 +161,7 @@ void HUD::setEffect(const char *img) mEffect1->setImageTexture(img); } -void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) +void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& value) { static const char *ids[] = { diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index de4228e87..013ad59f0 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -14,7 +14,7 @@ namespace MWGui public: HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); void setEffect(const char *img); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); void setTriangleCount(unsigned int count); void setBatchCount(unsigned int count); diff --git a/apps/openmw/mwgui/levelupdialog.cpp b/apps/openmw/mwgui/levelupdialog.cpp new file mode 100644 index 000000000..7dced94f5 --- /dev/null +++ b/apps/openmw/mwgui/levelupdialog.cpp @@ -0,0 +1,197 @@ +#include "levelupdialog.hpp" + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/creaturestats.hpp" +#include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/stat.hpp" + +#include +#include + +namespace MWGui +{ + + LevelupDialog::LevelupDialog(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_levelup_dialog.layout", parWindowManager) + { + getWidget(mOkButton, "OkButton"); + getWidget(mClassImage, "ClassImage"); + getWidget(mLevelText, "LevelText"); + + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onOkButtonClicked); + + for (int i=1; i<9; ++i) + { + MyGUI::TextBox* t; + getWidget(t, "AttribVal" + boost::lexical_cast(i)); + + MyGUI::Button* b; + getWidget(b, "Attrib" + boost::lexical_cast(i)); + b->setUserData (i-1); + b->eventMouseButtonClick += MyGUI::newDelegate(this, &LevelupDialog::onAttributeClicked); + mAttributes.push_back(b); + + mAttributeValues.push_back(t); + + getWidget(t, "AttribMultiplier" + boost::lexical_cast(i)); + + mAttributeMultipliers.push_back(t); + } + + int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5; + for (int i=0; i<3; ++i) + { + MyGUI::ImageBox* image = mMainWidget->createWidget("ImageBox", MyGUI::IntCoord(curX,250,16,16), MyGUI::Align::Default); + image->setImageTexture ("icons\\tx_goldicon.dds"); + curX += 24+2; + mCoins.push_back(image); + } + + center(); + } + + void LevelupDialog::setAttributeValues() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); + MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); + + for (int i=0; i<8; ++i) + { + int val = creatureStats.getAttribute (i).getBase (); + if (std::find(mSpentAttributes.begin(), mSpentAttributes.end(), i) != mSpentAttributes.end()) + { + val += pcStats.getLevelupAttributeMultiplier (i); + } + + if (val >= 100) + val = 100; + + mAttributeValues[i]->setCaption(boost::lexical_cast(val)); + } + } + + + void LevelupDialog::resetCoins () + { + int curX = mMainWidget->getWidth()/2 - (16 + 2) * 1.5; + for (int i=0; i<3; ++i) + { + MyGUI::ImageBox* image = mCoins[i]; + image->setCoord(MyGUI::IntCoord(curX,250,16,16)); + curX += 24+2; + } + } + + void LevelupDialog::assignCoins () + { + resetCoins(); + for (unsigned int i=0; igetCaption() == "" ? 0 : 30; + + MyGUI::IntPoint pos = mAttributes[attribute]->getAbsolutePosition() - mMainWidget->getAbsolutePosition() - MyGUI::IntPoint(24+xdiff,-4); + image->setPosition(pos); + } + + setAttributeValues(); + } + + void LevelupDialog::open() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); + MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); + + center(); + + mSpentAttributes.clear(); + resetCoins(); + + setAttributeValues(); + + // set class image + const ESM::Class& playerClass = MWBase::Environment::get().getWorld ()->getPlayer ().getClass (); + // retrieve the ID to this class + std::string classId; + std::map list = MWBase::Environment::get().getWorld()->getStore ().classes.list; + for (std::map::iterator it = list.begin(); it != list.end(); ++it) + { + if (playerClass.mName == it->second.mName) + classId = it->first; + } + mClassImage->setImageTexture ("textures\\levelup\\" + classId + ".dds"); + + /// \todo replace this with INI-imported texts + int level = creatureStats.getLevel ()+1; + mLevelText->setCaptionWithReplacing("#{sLevelUpMenu1} " + boost::lexical_cast(level)); + + 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)); + } + } + + void LevelupDialog::onOkButtonClicked (MyGUI::Widget* sender) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + MWMechanics::CreatureStats& creatureStats = MWWorld::Class::get(player).getCreatureStats (player); + MWMechanics::NpcStats& pcStats = MWWorld::Class::get(player).getNpcStats (player); + + if (mSpentAttributes.size() < 3) + MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage36}", std::vector()); + else + { + // increase attributes + for (int i=0; i<3; ++i) + { + MWMechanics::Stat& attribute = creatureStats.getAttribute(mSpentAttributes[i]); + attribute.setBase (attribute.getBase () + pcStats.getLevelupAttributeMultiplier (mSpentAttributes[i])); + + if (attribute.getBase() >= 100) + attribute.setBase(100); + } + + // "When you gain a level, in addition to increasing three primary attributes, your Health + // will automatically increase by 10% of your Endurance attribute. If you increased Endurance this level, + // the Health increase is calculated from the increased Endurance" + creatureStats.increaseLevelHealthBonus (creatureStats.getAttribute(ESM::Attribute::Endurance).getBase() * 0.1f); + + creatureStats.setLevel (creatureStats.getLevel()+1); + pcStats.levelUp (); + + mWindowManager.removeGuiMode (GM_Levelup); + } + + } + + void LevelupDialog::onAttributeClicked (MyGUI::Widget *sender) + { + int attribute = *sender->getUserData(); + + std::vector::iterator found = std::find(mSpentAttributes.begin(), mSpentAttributes.end(), attribute); + if (found != mSpentAttributes.end()) + mSpentAttributes.erase (found); + else + { + if (mSpentAttributes.size() == 3) + mSpentAttributes[2] = attribute; + else + mSpentAttributes.push_back(attribute); + } + assignCoins(); + } +} diff --git a/apps/openmw/mwgui/levelupdialog.hpp b/apps/openmw/mwgui/levelupdialog.hpp new file mode 100644 index 000000000..f5b24530d --- /dev/null +++ b/apps/openmw/mwgui/levelupdialog.hpp @@ -0,0 +1,39 @@ +#ifndef MWGUI_LEVELUPDIALOG_H +#define MWGUI_LEVELUPDIALOG_H + +#include "window_base.hpp" + +namespace MWGui +{ + + class LevelupDialog : public WindowBase + { + public: + LevelupDialog(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + private: + MyGUI::Button* mOkButton; + MyGUI::ImageBox* mClassImage; + MyGUI::TextBox* mLevelText; + + std::vector mAttributes; + std::vector mAttributeValues; + std::vector mAttributeMultipliers; + std::vector mCoins; + + std::vector mSpentAttributes; + + void onOkButtonClicked (MyGUI::Widget* sender); + void onAttributeClicked (MyGUI::Widget* sender); + + void assignCoins(); + void resetCoins(); + + void setAttributeValues(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index f92e4ee4f..ea7b44259 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -3,10 +3,13 @@ #include #include +#include +#include #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" +#include "../mwworld/player.hpp" using namespace MWGui; @@ -254,18 +257,24 @@ MapWindow::MapWindow(MWBase::WindowManager& parWindowManager) : getWidget(mLocalMap, "LocalMap"); getWidget(mGlobalMap, "GlobalMap"); - getWidget(mPlayerArrow, "Compass"); + getWidget(mGlobalMapImage, "GlobalMapImage"); + getWidget(mPlayerArrowLocal, "CompassLocal"); + getWidget(mPlayerArrowGlobal, "CompassGlobal"); + + mGlobalMap->setVisible (false); getWidget(mButton, "WorldButton"); mButton->eventMouseButtonClick += MyGUI::newDelegate(this, &MapWindow::onWorldButtonClicked); mButton->setCaptionWithReplacing("#{sWorld}"); - MyGUI::Button* eventbox; - getWidget(eventbox, "EventBox"); - eventbox->eventMouseDrag += MyGUI::newDelegate(this, &MapWindow::onMouseDrag); - eventbox->eventMouseButtonPressed += MyGUI::newDelegate(this, &MapWindow::onDragStart); + 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, mPlayerArrow, this); + LocalMapBase::init(mLocalMap, mPlayerArrowLocal, this); } void MapWindow::setCellName(const std::string& cellName) @@ -273,24 +282,54 @@ void MapWindow::setCellName(const std::string& cellName) setTitle(cellName); } +void MapWindow::addVisitedLocation(const std::string& name, int x, int y) +{ + const int cellSize = 24; + + int size = 24 * 61; + + MyGUI::IntCoord widgetCoord( + (x+30)*cellSize+6, + (size-1) - (y+30)*cellSize+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", "TextToolTip"); + markerWidget->setUserString("Caption_Text", 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); +} + void MapWindow::onDragStart(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; - if (!mGlobal) - mLastDragPos = MyGUI::IntPoint(_left, _top); + mLastDragPos = MyGUI::IntPoint(_left, _top); } void MapWindow::onMouseDrag(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id) { if (_id!=MyGUI::MouseButton::Left) return; - if (!mGlobal) - { - MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + MyGUI::IntPoint diff = MyGUI::IntPoint(_left, _top) - mLastDragPos; - mLastDragPos = MyGUI::IntPoint(_left, _top); - } + if (!mGlobal) + mLocalMap->setViewOffset( mLocalMap->getViewOffset() + diff ); + else + mGlobalMap->setViewOffset( mGlobalMap->getViewOffset() + diff ); + + + mLastDragPos = MyGUI::IntPoint(_left, _top); } void MapWindow::onWorldButtonClicked(MyGUI::Widget* _sender) @@ -307,3 +346,41 @@ void MapWindow::onPinToggled() { mWindowManager.setMinimapVisibility(!mPinned); } + +void MapWindow::open() +{ + mGlobalMapImage->setImageTexture("GlobalMap.png"); + + int size = 24 * 61; + + mGlobalMap->setCanvasSize (size, size); + mGlobalMapImage->setSize(size, size); + + for (unsigned int i=0; igetChildCount (); ++i) + { + if (mGlobalMapImage->getChildAt (i)->getName().substr(0,6) == "Marker") + mGlobalMapImage->getChildAt (i)->castType()->setImageResource("DoorMarker"); + } + + 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().z); + + float worldX = ((pos.x / 8192.f-0.5) / 30.f+1)/2.f; + float worldY = ((pos.z / 8192.f+1.5) / 30.f+1)/2.f; + + // 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(size * worldX - 16, size * 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); + } + + mPlayerArrowGlobal->setImageTexture ("textures\\compass.dds"); +} diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index 1203233bf..a8b5b9cb9 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -62,17 +62,26 @@ namespace MWGui void setCellName(const std::string& cellName); + void addVisitedLocation(const std::string& name, int x, int y); // adds the marker to the global map + + 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); MyGUI::ScrollView* mGlobalMap; - MyGUI::ImageBox* mPlayerArrow; + MyGUI::ImageBox* mGlobalMapImage; + MyGUI::ImageBox* mPlayerArrowLocal; + MyGUI::ImageBox* mPlayerArrowGlobal; MyGUI::Button* mButton; MyGUI::IntPoint mLastDragPos; bool mGlobal; + MyGUI::Button* mEventBoxGlobal; + MyGUI::Button* mEventBoxLocal; + protected: virtual void onPinToggled(); }; diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index 7e1adcf8b..64aa1dc21 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -20,8 +20,11 @@ namespace MWGui GM_Dialogue, // NPC interaction GM_Barter, GM_Rest, + GM_RestBed, GM_SpellBuying, + GM_Levelup, + // Startup character creation dialogs GM_Name, GM_Race, diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 15328ca74..40e5811a9 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -40,7 +40,7 @@ RaceDialog::RaceDialog(MWBase::WindowManager& parWindowManager) getWidget(mHeadRotate, "HeadRotate"); mHeadRotate->setScrollRange(50); - mHeadRotate->setScrollPosition(20); + mHeadRotate->setScrollPosition(25); mHeadRotate->setScrollViewPage(10); mHeadRotate->eventScrollChangePosition += MyGUI::newDelegate(this, &RaceDialog::onHeadRotate); diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 823f7d307..984c7d1ae 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -134,21 +134,21 @@ void ReviewDialog::setBirthSign(const std::string& signId) } } -void ReviewDialog::setHealth(const MWMechanics::DynamicStat& value) +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) +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) +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()); diff --git a/apps/openmw/mwgui/review.hpp b/apps/openmw/mwgui/review.hpp index 058e3cff3..2b0740234 100644 --- a/apps/openmw/mwgui/review.hpp +++ b/apps/openmw/mwgui/review.hpp @@ -35,9 +35,9 @@ namespace MWGui void setClass(const ESM::Class& class_); void setBirthSign (const std::string &signId); - void setHealth(const MWMechanics::DynamicStat& value); - void setMagicka(const MWMechanics::DynamicStat& value); - void setFatigue(const MWMechanics::DynamicStat& value); + void setHealth(const MWMechanics::DynamicStat& value); + void setMagicka(const MWMechanics::DynamicStat& value); + void setFatigue(const MWMechanics::DynamicStat& value); void setAttribute(ESM::Attribute::AttributeID attributeId, const MWMechanics::Stat& value); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index d1e206a95..cdfe4d2b6 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -122,6 +122,7 @@ namespace MWGui getWidget(mInvertYButton, "InvertYButton"); getWidget(mUISensitivitySlider, "UISensitivitySlider"); getWidget(mCameraSensitivitySlider, "CameraSensitivitySlider"); + getWidget(mGammaSlider, "GammaSlider"); mSubtitlesButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mCrosshairButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -143,6 +144,7 @@ namespace MWGui mViewDistanceSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mAnisotropySlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); + mGammaSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onSliderChangePosition); mShadowsEnabledButton->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); mShadowsLargeDistance->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onButtonToggled); @@ -200,6 +202,14 @@ namespace MWGui getWidget(fovText, "FovText"); fovText->setCaption("Field of View (" + boost::lexical_cast(int(Settings::Manager::getFloat("field of view", "General"))) + ")"); + float gammaVal = (Settings::Manager::getFloat("gamma", "Video")-0.1f)/(3.f-0.1f); + mGammaSlider->setScrollPosition(gammaVal * (mGammaSlider->getScrollRange()-1)); + MyGUI::TextBox* gammaText; + getWidget(gammaText, "GammaText"); + std::stringstream gamma; + gamma << std::setprecision (2) << Settings::Manager::getFloat("gamma", "Video"); + gammaText->setCaption("Gamma (" + gamma.str() + ")"); + float anisotropyVal = Settings::Manager::getInt("anisotropy", "General") / 16.0; mAnisotropySlider->setScrollPosition(anisotropyVal * (mAnisotropySlider->getScrollRange()-1)); std::string tf = Settings::Manager::getString("texture filtering", "General"); @@ -511,6 +521,15 @@ namespace MWGui fovText->setCaption("Field of View (" + boost::lexical_cast(int((1-val) * sFovMin + val * sFovMax)) + ")"); Settings::Manager::setFloat("field of view", "General", (1-val) * sFovMin + val * sFovMax); } + else if (scroller == mGammaSlider) + { + Settings::Manager::setFloat("gamma", "Video", (1-val) * 0.1f + val * 3.f); + MyGUI::TextBox* gammaText; + getWidget(gammaText, "GammaText"); + std::stringstream gamma; + gamma << std::setprecision (2) << Settings::Manager::getFloat("gamma", "Video"); + gammaText->setCaption("Gamma (" + gamma.str() + ")"); + } else if (scroller == mAnisotropySlider) { mAnisotropyLabel->setCaption("Anisotropy (" + boost::lexical_cast(int(val*16)) + ")"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index d1f35ed71..e878d0abe 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -40,6 +40,7 @@ namespace MWGui MyGUI::Button* mFPSButton; MyGUI::ScrollBar* mViewDistanceSlider; MyGUI::ScrollBar* mFOVSlider; + MyGUI::ScrollBar* mGammaSlider; MyGUI::ScrollBar* mAnisotropySlider; MyGUI::Button* mTextureFilteringButton; MyGUI::TextBox* mAnisotropyLabel; diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 98388cf52..6cc6eb94b 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -137,7 +137,7 @@ void StatsWindow::setValue (const std::string& id, const MWMechanics::Stat& } } -void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { static const char *ids[] = { @@ -150,7 +150,7 @@ void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicSta if (ids[i]==id) { std::string id (ids[i]); - setBar (id, id + "T", value.getCurrent(), value.getModified()); + setBar (id, id + "T", static_cast(value.getCurrent()), static_cast(value.getModified())); // health, magicka, fatigue tooltip MyGUI::Widget* w; @@ -236,12 +236,21 @@ void StatsWindow::configureSkills (const std::vector& major, const std::vec void StatsWindow::onFrame () { - if (mMainWidget->getVisible()) + 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()); setBirthSign(MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 73c4706dd..75f8c568b 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -32,7 +32,7 @@ namespace MWGui /// 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 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); diff --git a/apps/openmw/mwgui/text_input.cpp b/apps/openmw/mwgui/text_input.cpp index 9d5ba9896..3dbe75165 100644 --- a/apps/openmw/mwgui/text_input.cpp +++ b/apps/openmw/mwgui/text_input.cpp @@ -47,10 +47,22 @@ void TextInputDialog::open() void TextInputDialog::onOkClicked(MyGUI::Widget* _sender) { - eventDone(this); + if (mTextEdit->getCaption() == "") + { + mWindowManager.messageBox ("#{sNotifyMessage37}", std::vector()); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); } void TextInputDialog::onTextAccepted(MyGUI::Edit* _sender) { - eventDone(this); + if (mTextEdit->getCaption() == "") + { + mWindowManager.messageBox ("#{sNotifyMessage37}", std::vector()); + MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + } + else + eventDone(this); } diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp new file mode 100644 index 000000000..cc9019f2b --- /dev/null +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -0,0 +1,213 @@ +#include "waitdialog.hpp" + +#include + +#include + +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" +#include "../mwbase/environment.hpp" + +#include "../mwworld/timestamp.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" + +#include "widgets.hpp" + + +namespace MWGui +{ + + WaitDialogProgressBar::WaitDialogProgressBar(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_wait_dialog_progressbar.layout", parWindowManager) + { + getWidget(mProgressBar, "ProgressBar"); + getWidget(mProgressText, "ProgressText"); + } + + void WaitDialogProgressBar::open() + { + center(); + } + + void WaitDialogProgressBar::setProgress (int cur, int total) + { + mProgressBar->setProgressRange (total); + mProgressBar->setProgressPosition (cur); + mProgressText->setCaption(boost::lexical_cast(cur) + "/" + boost::lexical_cast(total)); + } + + // --------------------------------------------------------------------------------------------------------- + + WaitDialog::WaitDialog(MWBase::WindowManager &parWindowManager) + : WindowBase("openmw_wait_dialog.layout", parWindowManager) + , mProgressBar(parWindowManager) + , mWaiting(false) + , mSleeping(false) + , mHours(1) + , mRemainingTime(0.05) + { + getWidget(mDateTimeText, "DateTimeText"); + getWidget(mRestText, "RestText"); + getWidget(mHourText, "HourText"); + getWidget(mHourSlider, "HourSlider"); + getWidget(mUntilHealedButton, "UntilHealedButton"); + getWidget(mWaitButton, "WaitButton"); + getWidget(mCancelButton, "CancelButton"); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onCancelButtonClicked); + mUntilHealedButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onUntilHealedButtonClicked); + mWaitButton->eventMouseButtonClick += MyGUI::newDelegate(this, &WaitDialog::onWaitButtonClicked); + + mHourSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &WaitDialog::onHourSliderChangedPosition); + + mProgressBar.setVisible (false); + } + + void WaitDialog::open() + { + if (!MWBase::Environment::get().getWindowManager ()->getRestEnabled ()) + { + mWindowManager.popGuiMode (); + } + + int canRest = MWBase::Environment::get().getWorld ()->canRest (); + + if (canRest == 2) + { + // resting underwater or mid-air not allowed + mWindowManager.messageBox ("#{sNotifyMessage1}", std::vector()); + mWindowManager.popGuiMode (); + } + + setCanRest(canRest == 0); + + onHourSliderChangedPosition(mHourSlider, 0); + mHourSlider->setScrollPosition (0); + + // http://www.uesp.net/wiki/Lore:Calendar + std::string month; + int m = MWBase::Environment::get().getWorld ()->getMonth (); + if (m == 0) + month = "#{sMonthMorningstar}"; + else if (m == 1) + month = "#{sMonthSunsdawn}"; + else if (m == 2) + month = "#{sMonthFirstseed}"; + else if (m == 3) + month = "#{sMonthRainshand}"; + else if (m == 4) + month = "#{sMonthSecondseed}"; + else if (m == 5) + month = "#{sMonthMidyear}"; + else if (m == 6) + month = "#{sMonthSunsheight}"; + else if (m == 7) + month = "#{sMonthLastseed}"; + else if (m == 8) + month = "#{sMonthHeartfire}"; + else if (m == 9) + month = "#{sMonthFrostfall}"; + else if (m == 10) + month = "#{sMonthSunsdusk}"; + else if (m == 11) + month = "#{sMonthEveningstar}"; + + int hour = MWBase::Environment::get().getWorld ()->getTimeStamp ().getHour (); + bool pm = hour >= 12; + if (hour >= 13) hour -= 12; + + std::string dateTimeText = + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getDay ()+1) + " " + + month + " (#{sDay} " + boost::lexical_cast(MWBase::Environment::get().getWorld ()->getTimeStamp ().getDay ()+1) + + ") " + boost::lexical_cast(hour) + " " + (pm ? "#{sSaveMenuHelp05}" : "#{sSaveMenuHelp04}"); + + mDateTimeText->setCaptionWithReplacing (dateTimeText); + } + + void WaitDialog::onUntilHealedButtonClicked(MyGUI::Widget* sender) + { + startWaiting(); + } + + void WaitDialog::onWaitButtonClicked(MyGUI::Widget* sender) + { + startWaiting(); + } + + void WaitDialog::startWaiting () + { + MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.2); + setVisible(false); + mProgressBar.setVisible (true); + mWaiting = true; + mCurHour = 0; + mRemainingTime = 0.05; + mProgressBar.setProgress (0, mHours); + } + + void WaitDialog::onCancelButtonClicked(MyGUI::Widget* sender) + { + mWindowManager.popGuiMode (); + } + + void WaitDialog::onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position) + { + mHourText->setCaptionWithReplacing (boost::lexical_cast(position+1) + " #{sRestMenu2}"); + mHours = position+1; + } + + void WaitDialog::setCanRest (bool canRest) + { + mUntilHealedButton->setVisible(canRest); + mWaitButton->setCaptionWithReplacing (canRest ? "#{sRest}" : "#{sWait}"); + mRestText->setCaptionWithReplacing (canRest ? "#{sRestMenu3}" : "#{sRestIllegal}"); + + mSleeping = canRest; + + dynamic_cast(mMainWidget)->notifyChildrenSizeChanged(); + center(); + } + + void WaitDialog::onFrame(float dt) + { + if (!mWaiting) + return; + + mRemainingTime -= dt; + + if (mRemainingTime < 0) + { + mRemainingTime = 0.05; + ++mCurHour; + mProgressBar.setProgress (mCurHour, mHours); + + if (mCurHour <= mHours) + MWBase::Environment::get().getWorld ()->advanceTime (1); + } + + if (mCurHour > mHours) + stopWaiting(); + } + + void WaitDialog::stopWaiting () + { + MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); + mProgressBar.setVisible (false); + mWindowManager.popGuiMode (); + mWaiting = false; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats pcstats = MWWorld::Class::get(player).getNpcStats(player); + + // trigger levelup if possible + if (mSleeping && pcstats.getLevelProgress () >= 10) + { + mWindowManager.pushGuiMode (GM_Levelup); + } + } + +} diff --git a/apps/openmw/mwgui/waitdialog.hpp b/apps/openmw/mwgui/waitdialog.hpp new file mode 100644 index 000000000..4a401c0c6 --- /dev/null +++ b/apps/openmw/mwgui/waitdialog.hpp @@ -0,0 +1,66 @@ +#ifndef MWGUI_WAIT_DIALOG_H +#define MWGUI_WAIT_DIALOG_H + +#include "window_base.hpp" + +namespace MWGui +{ + + class WaitDialogProgressBar : public WindowBase + { + public: + WaitDialogProgressBar(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + void setProgress(int cur, int total); + + protected: + MyGUI::ProgressBar* mProgressBar; + MyGUI::TextBox* mProgressText; + }; + + class WaitDialog : public WindowBase + { + public: + WaitDialog(MWBase::WindowManager& parWindowManager); + + virtual void open(); + + void onFrame(float dt); + + void bedActivated() { setCanRest(true); } + + bool getSleeping() { return mWaiting && mSleeping; } + + protected: + MyGUI::TextBox* mDateTimeText; + MyGUI::TextBox* mRestText; + MyGUI::TextBox* mHourText; + MyGUI::ScrollBar* mHourSlider; + MyGUI::Button* mUntilHealedButton; + MyGUI::Button* mWaitButton; + MyGUI::Button* mCancelButton; + + bool mWaiting; + bool mSleeping; + int mCurHour; + int mHours; + float mRemainingTime; + + WaitDialogProgressBar mProgressBar; + + void onUntilHealedButtonClicked(MyGUI::Widget* sender); + void onWaitButtonClicked(MyGUI::Widget* sender); + void onCancelButtonClicked(MyGUI::Widget* sender); + void onHourSliderChangedPosition(MyGUI::ScrollBar* sender, size_t position); + + void setCanRest(bool canRest); + + void startWaiting(); + void stopWaiting(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index dca689471..33aa1886c 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -795,7 +795,6 @@ void MWDynamicStat::initialiseOverride() // --------------------------------------------------------------------------------------------------------------------- - void AutoSizedWidget::notifySizeChange (MyGUI::Widget* w) { if (w->getParent () != 0) @@ -869,29 +868,33 @@ void AutoSizedButton::setPropertyOverride(const std::string& _key, const std::st Box::Box() : mSpacing(4) + , mPadding(0) + , mAutoResize(false) { } -void Box::setPropertyOverride(const std::string& _key, const std::string& _value) -{ - if (_key == "Spacing") - { - mSpacing = MyGUI::utility::parseValue(_value); - } -} - 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) @@ -904,28 +907,43 @@ void HBox::align () { sizes.push_back(std::make_pair(aw->getRequestedSize (), hstretch)); total_width += aw->getRequestedSize ().width; + total_height = std::max(total_height, aw->getRequestedSize ().height); } else { - if (!hstretch) h_stretched_count ++; - sizes.push_back (std::make_pair(MyGUI::IntSize(0,0), true)); + sizes.push_back (std::make_pair(w->getSize(), hstretch)); + total_width += w->getSize().width; } 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 = (getSize().height - sizes[i].first.height) / 2; - int width = sizes[i].second ? sizes[i].first.width + (getSize().width - total_width)/h_stretched_count + 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 = sizes[i].first.height; + widgetCoord.height = height; w->setCoord(widgetCoord); curX += width; @@ -934,12 +952,33 @@ void HBox::align () } } +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(); +} + +void HBox::onWidgetDestroy(MyGUI::Widget* _widget) +{ + align(); +} + MyGUI::IntSize HBox::getRequestedSize () { MyGUI::IntSize size(0,0); @@ -954,6 +993,19 @@ MyGUI::IntSize HBox::getRequestedSize () 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; } @@ -963,7 +1015,69 @@ MyGUI::IntSize HBox::getRequestedSize () void VBox::align () { - // not yet implemented + 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 (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) @@ -972,6 +1086,12 @@ void VBox::setSize (const MyGUI::IntSize& _value) align(); } +void VBox::setCoord (const MyGUI::IntCoord& _value) +{ + MyGUI::Widget::setCoord (_value); + align(); +} + MyGUI::IntSize VBox::getRequestedSize () { MyGUI::IntSize size(0,0); @@ -986,6 +1106,29 @@ MyGUI::IntSize VBox::getRequestedSize () 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::onWidgetDestroy(MyGUI::Widget* _widget) +{ + align(); +} diff --git a/apps/openmw/mwgui/widgets.hpp b/apps/openmw/mwgui/widgets.hpp index 16c2adec9..6298ea77d 100644 --- a/apps/openmw/mwgui/widgets.hpp +++ b/apps/openmw/mwgui/widgets.hpp @@ -357,10 +357,13 @@ namespace MWGui protected: virtual void align() = 0; - virtual void setPropertyOverride(const std::string& _key, const std::string& _value); - + virtual void _setPropertyImpl(const std::string& _key, const std::string& _value); int mSpacing; // how much space to put between elements + + int mPadding; // outer padding + + bool mAutoResize; // auto resize the box so that it exactly fits all elements }; class HBox : public Box, public MyGUI::Widget @@ -369,10 +372,16 @@ namespace MWGui public: virtual void setSize (const MyGUI::IntSize &_value); + virtual void setCoord (const MyGUI::IntCoord &_value); protected: virtual void align(); virtual MyGUI::IntSize getRequestedSize(); + + 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 @@ -381,10 +390,16 @@ namespace MWGui public: virtual void setSize (const MyGUI::IntSize &_value); + virtual void setCoord (const MyGUI::IntCoord &_value); protected: virtual void align(); virtual MyGUI::IntSize getRequestedSize(); + + virtual void setPropertyOverride(const std::string& _key, const std::string& _value); + + virtual void onWidgetCreated(MyGUI::Widget* _widget); + virtual void onWidgetDestroy(MyGUI::Widget* _widget); }; } } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 2bbcfa9cc..a08a84b29 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -44,6 +44,8 @@ #include "spellwindow.hpp" #include "quickkeysmenu.hpp" #include "loadingscreen.hpp" +#include "levelupdialog.hpp" +#include "waitdialog.hpp" using namespace MWGui; @@ -70,6 +72,8 @@ WindowManager::WindowManager( , mSpellWindow(NULL) , mLoadingScreen(NULL) , mCharGen(NULL) + , mLevelupDialog(NULL) + , mWaitDialog(NULL) , mPlayerClass() , mPlayerName() , mPlayerRaceId() @@ -84,6 +88,7 @@ WindowManager::WindowManager( , mGarbageDialogs() , mShown(GW_ALL) , mAllowed(newGame ? GW_None : GW_ALL) + , mRestAllowed(newGame ? false : true) , mShowFPSLevel(fpsLevel) , mFPS(0.0f) , mTriangleCount(0) @@ -147,6 +152,8 @@ WindowManager::WindowManager( mAlchemyWindow = new AlchemyWindow(*this); mSpellWindow = new SpellWindow(*this); mQuickKeysMenu = new QuickKeysMenu(*this); + mLevelupDialog = new LevelupDialog(*this); + mWaitDialog = new WaitDialog(*this); mLoadingScreen = new LoadingScreen(mOgre->getScene (), mOgre->getWindow (), *this); mLoadingScreen->onResChange (w,h); @@ -200,6 +207,8 @@ WindowManager::~WindowManager() delete mAlchemyWindow; delete mSpellWindow; delete mLoadingScreen; + delete mLevelupDialog; + delete mWaitDialog; cleanupGarbage(); @@ -247,6 +256,8 @@ void WindowManager::updateVisible() mAlchemyWindow->setVisible(false); mSpellWindow->setVisible(false); mQuickKeysMenu->setVisible(false); + mLevelupDialog->setVisible(false); + mWaitDialog->setVisible(false); mHud->setVisible(true); @@ -298,6 +309,16 @@ void WindowManager::updateVisible() 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: @@ -395,7 +416,7 @@ void WindowManager::setValue (int parSkill, const MWMechanics::Stat& valu mPlayerSkillValues[parSkill] = value; } -void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) +void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { mStatsWindow->setValue (id, value); mHud->setValue (id, value); @@ -532,6 +553,8 @@ void WindowManager::onFrame (float frameDuration) mStatsWindow->onFrame(); + mWaitDialog->onFrame(frameDuration); + mHud->onFrame(frameDuration); mDialogueWindow->checkReferenceAvailable(); @@ -547,7 +570,10 @@ void WindowManager::changeCell(MWWorld::Ptr::CellStore* cell) { std::string name; if (cell->cell->mName != "") + { name = cell->cell->mName; + mMap->addVisitedLocation (name, cell->cell->getGridX (), cell->cell->getGridY ()); + } else { const ESM::Region* region = MWBase::Environment::get().getWorld()->getStore().regions.search(cell->cell->mRegion); @@ -923,3 +949,13 @@ void WindowManager::loadingDone () { mLoadingScreen->loadingDone (); } + +bool WindowManager::getPlayerSleeping () +{ + return mWaitDialog->getSleeping(); +} + +void WindowManager::addVisitedLocation(const std::string& name, int x, int y) +{ + mMap->addVisitedLocation (name, x, y); +} diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index e16b03e43..47461f877 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -62,6 +62,8 @@ namespace MWGui class AlchemyWindow; class QuickKeysMenu; class LoadingScreen; + class LevelupDialog; + class WaitDialog; class WindowManager : public MWBase::WindowManager { @@ -117,7 +119,7 @@ namespace MWGui ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::Stat& value); virtual void setValue (int parSkill, const MWMechanics::Stat& value); - virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + virtual void setValue (const std::string& id, const MWMechanics::DynamicStat& value); virtual void setValue (const std::string& id, const std::string& value); virtual void setValue (const std::string& id, int value); @@ -170,6 +172,8 @@ namespace MWGui virtual void allowMouse(); virtual void notifyInputActionBound(); + virtual void addVisitedLocation(const std::string& name, int x, int y); + virtual void removeDialog(OEngine::GUI::Layout* dialog); ///< Hides dialog and schedules dialog to be deleted. virtual void messageBox (const std::string& message, const std::vector& buttons); @@ -199,6 +203,11 @@ namespace MWGui virtual void setLoadingProgress (const std::string& stage, int depth, int current, int total); virtual void loadingDone(); + virtual void enableRest() { mRestAllowed = true; } + virtual bool getRestEnabled() { return mRestAllowed; } + + virtual bool getPlayerSleeping(); + private: OEngine::GUI::MyGUIManager *mGuiManager; HUD *mHud; @@ -224,6 +233,8 @@ namespace MWGui SpellWindow* mSpellWindow; QuickKeysMenu* mQuickKeysMenu; LoadingScreen* mLoadingScreen; + LevelupDialog* mLevelupDialog; + WaitDialog* mWaitDialog; CharacterCreation* mCharGen; @@ -241,7 +252,7 @@ namespace MWGui std::map > mPlayerAttributes; SkillList mPlayerMajorSkills, mPlayerMinorSkills; std::map > mPlayerSkillValues; - MWMechanics::DynamicStat mPlayerHealth, mPlayerMagicka, mPlayerFatigue; + MWMechanics::DynamicStat mPlayerHealth, mPlayerMagicka, mPlayerFatigue; MyGUI::Gui *mGui; // Gui @@ -258,6 +269,8 @@ namespace MWGui allow() and disableAll(). */ GuiWindow mAllowed; + // is the rest window allowed? + bool mRestAllowed; void updateVisible(); // Update visibility of all windows based on mode, shown and allowed settings diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index b198785d2..c3e131440 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -190,6 +190,9 @@ namespace MWInput case A_ToggleWeapon: toggleWeapon (); break; + case A_Rest: + rest(); + break; case A_ToggleSpell: toggleSpell (); break; @@ -543,6 +546,15 @@ namespace MWInput } } + void InputManager::rest() + { + if (!mWindows.getRestEnabled () || mWindows.isGuiMode ()) + return; + + /// \todo check if resting is currently allowed (enemies nearby?) + mWindows.pushGuiMode (MWGui::GM_Rest); + } + void InputManager::screenshot() { mEngine.screenshot(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 7d03f1d5b..5e6169f68 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -168,6 +168,7 @@ namespace MWInput void toggleWalking(); void toggleAutoMove(); void exitNow(); + void rest(); void quickKey (int index); void showQuickKeysMenu(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bd037df9f..b4cc40fec 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -68,7 +68,7 @@ namespace MWMechanics creatureStats.getMagicEffects().get (EffectKey (84)).mMagnitude * 0.1 + 0.5; creatureStats.getHealth().setBase( - static_cast (0.5 * (strength + endurance))); + static_cast (0.5 * (strength + endurance)) + creatureStats.getLevelHealthBonus ()); creatureStats.getMagicka().setBase( static_cast (intelligence + magickaFactor * intelligence)); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 91a9225fe..fc0523141 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -9,6 +9,21 @@ namespace MWMechanics { + CreatureStats::CreatureStats() + : mLevelHealthBonus(0.f) + { + } + + void CreatureStats::increaseLevelHealthBonus (float value) + { + mLevelHealthBonus += value; + } + + float CreatureStats::getLevelHealthBonus () const + { + return mLevelHealthBonus; + } + const AiSequence& CreatureStats::getAiSequence() const { return mAiSequence; @@ -40,17 +55,17 @@ namespace MWMechanics return mAttributes[index]; } - const DynamicStat &CreatureStats::getHealth() const + const DynamicStat &CreatureStats::getHealth() const { return mDynamic[0]; } - const DynamicStat &CreatureStats::getMagicka() const + const DynamicStat &CreatureStats::getMagicka() const { return mDynamic[1]; } - const DynamicStat &CreatureStats::getFatigue() const + const DynamicStat &CreatureStats::getFatigue() const { return mDynamic[2]; } @@ -103,22 +118,22 @@ namespace MWMechanics return mAttributes[index]; } - DynamicStat &CreatureStats::getHealth() + DynamicStat &CreatureStats::getHealth() { return mDynamic[0]; } - DynamicStat &CreatureStats::getMagicka() + DynamicStat &CreatureStats::getMagicka() { return mDynamic[1]; } - DynamicStat &CreatureStats::getFatigue() + DynamicStat &CreatureStats::getFatigue() { return mDynamic[2]; } - DynamicStat &CreatureStats::getDynamic(int index) + DynamicStat &CreatureStats::getDynamic(int index) { if (index < 0 || index > 2) { throw std::runtime_error("dynamic stat index is out of range"); @@ -154,17 +169,17 @@ namespace MWMechanics mAttributes[index] = value; } - void CreatureStats::setHealth(const DynamicStat &value) + void CreatureStats::setHealth(const DynamicStat &value) { mDynamic[0] = value; } - void CreatureStats::setMagicka(const DynamicStat &value) + void CreatureStats::setMagicka(const DynamicStat &value) { mDynamic[1] = value; } - void CreatureStats::setFatigue(const DynamicStat &value) + void CreatureStats::setFatigue(const DynamicStat &value) { mDynamic[2] = value; } diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index a6fb6779a..7a1e46f56 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -19,7 +19,7 @@ namespace MWMechanics class CreatureStats { Stat mAttributes[8]; - DynamicStat mDynamic[3]; // health, magicka, fatigue + DynamicStat mDynamic[3]; // health, magicka, fatigue int mLevel; Spells mSpells; ActiveSpells mActiveSpells; @@ -30,15 +30,18 @@ namespace MWMechanics int mAlarm; AiSequence mAiSequence; + float mLevelHealthBonus; + public: + CreatureStats(); const Stat & getAttribute(int index) const; - const DynamicStat & getHealth() const; + const DynamicStat & getHealth() const; - const DynamicStat & getMagicka() const; + const DynamicStat & getMagicka() const; - const DynamicStat & getFatigue() const; + const DynamicStat & getFatigue() const; const Spells & getSpells() const; @@ -59,13 +62,13 @@ namespace MWMechanics Stat & getAttribute(int index); - DynamicStat & getHealth(); + DynamicStat & getHealth(); - DynamicStat & getMagicka(); + DynamicStat & getMagicka(); - DynamicStat & getFatigue(); + DynamicStat & getFatigue(); - DynamicStat & getDynamic(int index); + DynamicStat & getDynamic(int index); Spells & getSpells(); @@ -76,11 +79,11 @@ namespace MWMechanics void setAttribute(int index, const Stat &value); - void setHealth(const DynamicStat &value); + void setHealth(const DynamicStat &value); - void setMagicka(const DynamicStat &value); + void setMagicka(const DynamicStat &value); - void setFatigue(const DynamicStat &value); + void setFatigue(const DynamicStat &value); void setSpells(const Spells &spells); @@ -104,6 +107,10 @@ namespace MWMechanics float getFatigueTerm() const; ///< Return effective fatigue + + // small hack to allow the fact that Health permanently increases by 10% of endurance on each level up + void increaseLevelHealthBonus(float value); + float getLevelHealthBonus() const; }; } diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index a0b50f630..5ffc99579 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -4,6 +4,8 @@ #include #include +#include + #include #include #include @@ -12,10 +14,17 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/soundmanager.hpp" MWMechanics::NpcStats::NpcStats() : mMovementFlags (0), mDrawState (DrawState_Nothing) -{} +, mLevelProgress(0) +{ + mSkillIncreases.resize (ESM::Attribute::Length); + for (int i=0; i (base)!=level) + { + // skill leveled up + increaseSkill(skillIndex, class_, false); + } + else + getSkill (skillIndex).setBase (base); +} + +void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &class_, bool preserveProgress) +{ + float base = getSkill (skillIndex).getBase(); + + int level = static_cast (base); + + if (level >= 100) + return; + + if (preserveProgress) + base += 1; + else base = level+1; + // if this is a major or minor skill of the class, increase level progress + bool levelProgress = false; + for (int i=0; i<2; ++i) + for (int j=0; j<5; ++j) + { + int skill = class_.mData.mSkills[j][i]; + if (skill == skillIndex) + levelProgress = true; + } + + mLevelProgress += levelProgress; + + // check the attribute this skill belongs to + const ESM::Skill* skill = MWBase::Environment::get().getWorld ()->getStore ().skills.find(skillIndex); + ++mSkillIncreases[skill->mData.mAttribute]; + + // Play sound & skill progress notification + /// \todo check if character is the player, if levelling is ever implemented for NPCs + MWBase::Environment::get().getSoundManager ()->playSound ("skillraise", 1, 1); + + std::stringstream message; + message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) + % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") + % base; + MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), std::vector()); + + if (mLevelProgress >= 10) + { + // levelup is possible now + MWBase::Environment::get().getWindowManager ()->messageBox ("#{sLevelUpMsg}", std::vector()); + } + getSkill (skillIndex).setBase (base); } + +int MWMechanics::NpcStats::getLevelProgress () const +{ + return mLevelProgress; +} + +void MWMechanics::NpcStats::levelUp() +{ + mLevelProgress -= 10; + for (int i=0; i #include #include +#include #include "stat.hpp" #include "drawstate.hpp" @@ -45,6 +46,10 @@ namespace MWMechanics unsigned int mMovementFlags; Stat mSkill[27]; + int mLevelProgress; // 0-10 + + std::vector mSkillIncreases; // number of skill increases for each attribute + public: NpcStats(); @@ -73,6 +78,14 @@ namespace MWMechanics void useSkill (int skillIndex, const ESM::Class& class_, int usageType = -1); ///< Increase skill by usage. + + void increaseSkill (int skillIndex, const ESM::Class& class_, bool preserveProgress); + + int getLevelProgress() const; + + int getLevelupAttributeMultiplier(int attribute) const; + + void levelUp(); }; } diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 01c5d594a..c8852bff5 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -72,6 +72,8 @@ namespace MWRender CharacterPreview::~CharacterPreview () { Ogre::TextureManager::getSingleton().remove(mName); + mSceneMgr->destroyCamera (mName); + delete mAnimation; } diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp new file mode 100644 index 000000000..a0bfdd8e8 --- /dev/null +++ b/apps/openmw/mwrender/globalmap.cpp @@ -0,0 +1,148 @@ +#include "globalmap.hpp" + +#include + +#include +#include +#include +#include +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +#include +#include + +namespace MWRender +{ + + GlobalMap::GlobalMap(const std::string &cacheDir) + : mCacheDir(cacheDir) + { + } + + + void GlobalMap::render () + { + Ogre::TexturePtr tex; + + if (!boost::filesystem::exists(mCacheDir + "/GlobalMap.png")) + { + + int cellSize = 24; + + Ogre::Image image; + + int width = cellSize*61; + int height = cellSize*61; + + Ogre::uchar data[width * height * 3]; + + for (int x = -30; x <= 30; ++x) + { + for (int y = -30; y <= 30; ++y) + { + ESM::Land* land = MWBase::Environment::get().getWorld ()->getStore ().lands.search (x,y); + + if (land) + { + if (!land->isDataLoaded(ESM::Land::DATA_VHGT)) + { + land->loadData(ESM::Land::DATA_VHGT); + } + } + + for (int cellY=0; cellYmLandData->mHeights[vertexY * ESM::Land::LAND_SIZE + vertexX]; + + + if (landHeight >= 0) + { + if (landHeight >= hillHeight) + { + float factor = std::min(1.f, float(landHeight-hillHeight)/mountainHeight); + r = (hillColour.r * (1-factor) + mountainColour.r * factor) * 255; + g = (hillColour.g * (1-factor) + mountainColour.g * factor) * 255; + b = (hillColour.b * (1-factor) + mountainColour.b * factor) * 255; + } + else + { + float factor = std::min(1.f, float(landHeight)/hillHeight); + r = (groundColour.r * (1-factor) + hillColour.r * factor) * 255; + g = (groundColour.g * (1-factor) + hillColour.g * factor) * 255; + b = (groundColour.b * (1-factor) + hillColour.b * factor) * 255; + } + } + else + { + if (landHeight >= -100) + { + float factor = std::min(1.f, -1*landHeight/100.f); + r = (((waterShallowColour+groundColour)/2).r * (1-factor) + waterShallowColour.r * factor) * 255; + g = (((waterShallowColour+groundColour)/2).g * (1-factor) + waterShallowColour.g * factor) * 255; + b = (((waterShallowColour+groundColour)/2).b * (1-factor) + waterShallowColour.b * factor) * 255; + } + else + { + float factor = std::min(1.f, -1*(landHeight-100)/1000.f); + r = (waterShallowColour.r * (1-factor) + waterDeepColour.r * factor) * 255; + g = (waterShallowColour.g * (1-factor) + waterDeepColour.g * factor) * 255; + b = (waterShallowColour.b * (1-factor) + waterDeepColour.b * factor) * 255; + } + } + + } + else + { + r = waterDeepColour.r * 255; + g = waterDeepColour.g * 255; + b = waterDeepColour.b * 255; + } + + data[texelY * height * 3 + texelX * 3] = r; + data[texelY * height * 3 + texelX * 3+1] = g; + data[texelY * height * 3 + texelX * 3+2] = b; + } + } + } + } + + image.loadDynamicImage (data, width, height, Ogre::PF_B8G8R8); + + image.save (mCacheDir + "/GlobalMap.png"); + + tex = Ogre::TextureManager::getSingleton ().createManual ("GlobalMap.png", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, width, height, 0, Ogre::PF_B8G8R8, Ogre::TU_DEFAULT); + tex->loadImage(image); + } + else + tex = Ogre::TextureManager::getSingleton ().getByName ("GlobalMap.png"); + + tex->load(); + } + +} diff --git a/apps/openmw/mwrender/globalmap.hpp b/apps/openmw/mwrender/globalmap.hpp new file mode 100644 index 000000000..b7c199dcf --- /dev/null +++ b/apps/openmw/mwrender/globalmap.hpp @@ -0,0 +1,23 @@ +#ifndef _GAME_RENDER_GLOBALMAP_H +#define _GAME_RENDER_GLOBALMAP_H + +#include + +namespace MWRender +{ + + class GlobalMap + { + public: + GlobalMap(const std::string& cacheDir); + + void render(); + + private: + std::string mCacheDir; + }; + +} + +#endif + diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index b0e851d55..5c2b05aca 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -77,12 +77,6 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor bodyRaceID = "b_n_"+ref->base->mRace; std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower); - /*std::cout << "Race: " << ref->base->race ; - if(female) - std::cout << " Sex: Female" << " Height: " << race->data.height.female << "\n"; - else - std::cout << " Sex: Male" << " Height: " << race->data.height.male << "\n"; - */ mInsert = node; assert(mInsert); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c95b99572..99b82bd0c 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -35,6 +35,7 @@ #include "compositors.hpp" #include "npcanimation.hpp" #include "externalrendering.hpp" +#include "globalmap.hpp" using namespace MWRender; using namespace Ogre; @@ -43,7 +44,7 @@ namespace MWRender { RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const boost::filesystem::path& resDir, const boost::filesystem::path& cacheDir, OEngine::Physic::PhysicEngine* engine) - :mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine) + : mRendering(_rend), mObjects(mRendering), mActors(mRendering), mAmbientMode(0), mSunEnabled(0), mPhysicsEngine(engine) { // select best shader mode bool openGL = (Ogre::Root::getSingleton ().getRenderSystem ()->getName().find("OpenGL") != std::string::npos); @@ -100,7 +101,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const MaterialManager::getSingleton().setDefaultTextureFiltering(tfo); MaterialManager::getSingleton().setDefaultAnisotropy( (filter == "anisotropic") ? Settings::Manager::getInt("anisotropy", "General") : 1 ); - // Load resources + ResourceGroupManager::getSingleton ().declareResource ("GlobalMap.png", "Texture", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // causes light flicker in opengl when moving.. @@ -129,6 +131,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(0))); sh::Factory::getInstance ().setSharedParameter ("windDir_windSpeed", sh::makeProperty(new sh::Vector3(0.5, -0.8, 0.2))); sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty(new sh::Vector2(1, 0.6))); + sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( + Settings::Manager::getFloat ("gamma", "Video")))); applyCompositors(); @@ -160,6 +164,8 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const mDebugging = new Debugging(mMwRoot, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); + mGlobalMap = new GlobalMap(cacheDir.string()); + setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -176,6 +182,7 @@ RenderingManager::~RenderingManager () delete mOcclusionQuery; delete mCompositors; delete mWater; + delete mGlobalMap; } MWRender::SkyManager* RenderingManager::getSkyManager() @@ -275,13 +282,15 @@ RenderingManager::rotateObject( float *f = ptr.getRefData().getPosition().rot; rot.x += f[0], rot.y += f[1], rot.z += f[2]; } + 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); - + ptr.getRefData().getBaseNode()->setOrientation(xr * yr * zr); } + return force; } @@ -747,6 +756,11 @@ void RenderingManager::processChangedSettings(const Settings::CategorySettingVec sh::Factory::getInstance ().setShadersEnabled (Settings::Manager::getBool("shaders", "Objects")); mObjects.rebuildStaticGeometry (); } + else if (it->second == "gamma" && it->first == "Video") + { + sh::Factory::getInstance ().setSharedParameter ("gammaCorrection", sh::makeProperty(new sh::FloatValue( + Settings::Manager::getFloat ("gamma", "Video")))); + } else if (it->second == "shader mode" && it->first == "General") { sh::Language lang; @@ -887,4 +901,9 @@ void RenderingManager::setupExternalRendering (MWRender::ExternalRendering& rend rendering.setup (mRendering.getScene()); } +void RenderingManager::renderGlobalMap () +{ + mGlobalMap->render (); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e994e4909..24ec8b15b 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -44,6 +44,7 @@ namespace MWRender class Water; class Compositors; class ExternalRendering; + class GlobalMap; class RenderingManager: private RenderingInterface, public Ogre::WindowEventListener { @@ -194,6 +195,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList void setupExternalRendering (MWRender::ExternalRendering& rendering); + void renderGlobalMap(); + protected: virtual void windowResized(Ogre::RenderWindow* rw); virtual void windowClosed(Ogre::RenderWindow* rw); @@ -218,6 +221,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList MWRender::Water *mWater; + GlobalMap* mGlobalMap; + OEngine::Render::OgreRenderer &mRendering; MWRender::Objects mObjects; diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 59b9bca35..a4a9e99fd 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -31,7 +31,7 @@ op 0x2000e: PCGetRank implicit op 0x2000f: PCGetRank explicit op 0x20010: AiWander op 0x20011: AiWander, explicit reference -opcodes 0x20012-0x3ffff unused +op s 0x20012-0x3ffff unused Segment 4: (not implemented yet) @@ -183,4 +183,27 @@ op 0x2000172: GetStartingAngle op 0x2000173: GetStartingAngle, explicit reference op 0x2000174: ToggleVanityMode op 0x2000175-0x200018B: Get controls disabled -opcodes 0x200018C-0x3ffffff unused +op 0x200018C: GetLevel +op 0x200018D: GetLevel, explicit reference +op 0x200018E: SetLevel +op 0x200018F: SetLevel, explicit reference +op 0x2000190: GetPos +op 0x2000191: GetPosExplicit +op 0x2000192: SetPos +op 0x2000193: SetPosExplicit +op 0x2000194: GetStartingPos +op 0x2000195: GetStartingPosExplicit +op 0x2000196: Position +op 0x2000197: Position Explicit +op 0x2000198: PositionCell +op 0x2000199: PositionCell Explicit +op 0x200019a: PlaceItemCell +op 0x200019b: PlaceItem +op 0x200019c: PlaceAtPc +op 0x200019d: PlaceAtMe +op 0x200019e: PlaceAtMe Explicit +op 0x200019f: GetPcSleep +op 0x20001a0: ShowMap +op 0x20001a1: FillMap +opcodes 0x20001a2-0x3ffffff unused + diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index d740e5feb..66bb4e043 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -1,12 +1,17 @@ #include "guiextensions.hpp" +#include + #include #include #include #include +#include +#include + #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -30,6 +35,16 @@ namespace MWScript } }; + class OpEnableRest : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWBase::Environment::get().getWindowManager()->enableRest(); + } + }; + class OpShowDialogue : public Interpreter::Opcode0 { MWGui::GuiMode mDialogue; @@ -81,6 +96,47 @@ namespace MWScript } }; + class OpShowMap : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string cell = (runtime.getStringLiteral (runtime[0].mInteger)); + boost::algorithm::to_lower(cell); + runtime.pop(); + + // "Will match complete or partial cells, so ShowMap, "Vivec" will show cells Vivec and Vivec, Fred's House as well." + // http://www.uesp.net/wiki/Tes3Mod:ShowMap + + const ESMS::CellList::ExtCells& extCells = MWBase::Environment::get().getWorld ()->getStore ().cells.extCells; + for (ESMS::CellList::ExtCells::const_iterator it = extCells.begin(); it != extCells.end(); ++it) + { + std::string name = it->second->mName; + boost::algorithm::to_lower(name); + if (name.find(cell) != std::string::npos) + MWBase::Environment::get().getWindowManager()->addVisitedLocation (it->second->mName, it->first.first, it->first.second); + } + } + }; + + class OpFillMap : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + const ESMS::CellList::ExtCells& extCells = MWBase::Environment::get().getWorld ()->getStore ().cells.extCells; + for (ESMS::CellList::ExtCells::const_iterator it = extCells.begin(); it != extCells.end(); ++it) + { + std::string name = it->second->mName; + if (name != "") + MWBase::Environment::get().getWindowManager()->addVisitedLocation (name, it->first.first, it->first.second); + } + } + }; + + const int opcodeEnableBirthMenu = 0x200000e; const int opcodeEnableClassMenu = 0x200000f; const int opcodeEnableNameMenu = 0x2000010; @@ -95,6 +151,8 @@ namespace MWScript const int opcodeGetButtonPressed = 0x2000137; const int opcodeToggleFogOfWar = 0x2000145; const int opcodeToggleFullHelp = 0x2000151; + const int opcodeShowMap = 0x20001a0; + const int opcodeFillMap = 0x20001a1; void registerExtensions (Compiler::Extensions& extensions) { @@ -122,6 +180,9 @@ opcodeEnableStatsReviewMenu); extensions.registerInstruction ("togglefullhelp", "", opcodeToggleFullHelp); extensions.registerInstruction ("tfh", "", opcodeToggleFullHelp); + + extensions.registerInstruction ("showmap", "S", opcodeShowMap); + extensions.registerInstruction ("fillmap", "", opcodeFillMap); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -146,21 +207,20 @@ opcodeEnableStatsReviewMenu); interpreter.installSegment5 (opcodeEnableStatsMenu, new OpEnableWindow (MWGui::GW_Stats)); - /* Not done yet. Enabling rest mode is not really a gui - issue, it's a gameplay issue. - interpreter.installSegment5 (opcodeEnableRest, - new OpEnableDialogue (MWGui::GM_Rest)); - */ + new OpEnableRest ()); interpreter.installSegment5 (opcodeShowRestMenu, - new OpShowDialogue (MWGui::GM_Rest)); + new OpShowDialogue (MWGui::GM_RestBed)); interpreter.installSegment5 (opcodeGetButtonPressed, new OpGetButtonPressed); interpreter.installSegment5 (opcodeToggleFogOfWar, new OpToggleFogOfWar); interpreter.installSegment5 (opcodeToggleFullHelp, new OpToggleFullHelp); + + interpreter.installSegment5 (opcodeShowMap, new OpShowMap); + interpreter.installSegment5 (opcodeFillMap, new OpFillMap); } } } diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 864c1a1ee..a869f882b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -10,6 +10,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" @@ -20,6 +21,16 @@ namespace MWScript { namespace Misc { + class OpGetPcSleep : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.push (MWBase::Environment::get().getWindowManager ()->getPlayerSleeping()); + } + }; + class OpXBox : public Interpreter::Opcode0 { public: @@ -249,6 +260,7 @@ namespace MWScript const int opcodeTogglePathgrid = 0x2000146; const int opcodeDontSaveObject = 0x2000153; const int opcodeToggleVanityMode = 0x2000174; + const int opcodeGetPcSleep = 0x200019f; void registerExtensions (Compiler::Extensions& extensions) { @@ -273,6 +285,7 @@ namespace MWScript extensions.registerInstruction ("dontsaveobject", "", opcodeDontSaveObject); extensions.registerInstruction ("togglevanitymode", "", opcodeToggleVanityMode); extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); + extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -293,6 +306,7 @@ namespace MWScript interpreter.installSegment5 (opcodeToggleWater, new OpToggleWater); interpreter.installSegment5 (opcodeDontSaveObject, new OpDontSaveObject); interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode); + interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep); } } } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 292a163fe..66a5acae0 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -32,6 +32,42 @@ namespace MWScript { namespace Stats { + template + class OpGetLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = + MWWorld::Class::get (ptr) + .getCreatureStats (ptr) + .getLevel(); + + runtime.push (value); + } + }; + + template + class OpSetLevel : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer value = runtime[0].mInteger; + runtime.pop(); + + MWWorld::Class::get (ptr) + .getCreatureStats (ptr) + .setLevel(value); + } + }; + template class OpGetAttribute : public Interpreter::Opcode0 { @@ -592,6 +628,11 @@ namespace MWScript const int opcodeModDisposition = 0x200014d; const int opcodeModDispositionExplicit = 0x200014e; + const int opcodeGetLevel = 0x200018c; + const int opcodeGetLevelExplicit = 0x200018d; + const int opcodeSetLevel = 0x200018e; + const int opcodeSetLevelExplicit = 0x200018f; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -674,6 +715,9 @@ namespace MWScript extensions.registerInstruction("moddisposition","l",opcodeModDisposition, opcodeModDispositionExplicit); extensions.registerFunction("getpcrank",'l',"/S",opcodeGetPCRank,opcodeGetPCRankExplicit); + + extensions.registerInstruction("setlevel", "l", opcodeSetLevel, opcodeSetLevelExplicit); + extensions.registerFunction("getlevel", 'l', "", opcodeGetLevel, opcodeGetLevelExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -745,6 +789,12 @@ namespace MWScript interpreter.installSegment5(opcodeModDispositionExplicit,new OpModDisposition); interpreter.installSegment3(opcodeGetPCRank,new OpGetPCRank); interpreter.installSegment3(opcodeGetPCRankExplicit,new OpGetPCRank); + + interpreter.installSegment5 (opcodeGetLevel, new OpGetLevel); + interpreter.installSegment5 (opcodeGetLevelExplicit, new OpGetLevel); + interpreter.installSegment5 (opcodeSetLevel, new OpSetLevel); + interpreter.installSegment5 (opcodeSetLevelExplicit, new OpSetLevel); + } } } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 19d34d07d..38e827ea6 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -1,6 +1,10 @@ #include +#include +#include + #include +#include #include @@ -11,10 +15,11 @@ #include "../mwbase/environment.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwworld/manualref.hpp" #include "interpretercontext.hpp" #include "ref.hpp" -#include "OgreSceneNode.h" namespace MWScript { @@ -141,6 +146,368 @@ namespace MWScript } }; + template + class OpGetPos : 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(); + + if(axis == "x") + { + runtime.push(ptr.getRefData().getPosition().pos[0]); + } + else if(axis == "y") + { + runtime.push(ptr.getRefData().getPosition().pos[1]); + } + else if(axis == "z") + { + runtime.push(ptr.getRefData().getPosition().pos[2]); + } + else + throw std::runtime_error ("invalid rotation axis: " + axis); + } + }; + + template + class OpSetPos : 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 pos = runtime[0].mFloat; + runtime.pop(); + + float ax = ptr.getRefData().getPosition().pos[0]; + float ay = ptr.getRefData().getPosition().pos[1]; + float az = ptr.getRefData().getPosition().pos[2]; + + if(axis == "x") + { + MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); + } + else if(axis == "y") + { + MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); + } + else if(axis == "z") + { + MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); + } + else + throw std::runtime_error ("invalid axis: " + axis); + } + }; + + template + class OpGetStartingPos : 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(); + + if(axis == "x") + { + runtime.push(ptr.getCellRef().mPos.pos[0]); + } + else if(axis == "y") + { + runtime.push(ptr.getCellRef().mPos.pos[1]); + } + else if(axis == "z") + { + runtime.push(ptr.getCellRef().mPos.pos[2]); + } + else + throw std::runtime_error ("invalid axis: " + axis); + } + }; + + template + class OpPositionCell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::CellStore* store = 0; + try + { + store = MWBase::Environment::get().getWorld()->getInterior(cellID); + } + catch(std::exception &e) + { + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + if(cell) + { + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + } + } + if(store) + { + MWBase::Environment::get().getWorld()->moveObject(ptr,*store,x,y,z); + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + if(ptr.getTypeName() == typeid(ESM::NPC).name())//some morrowind oddity + { + ax = ax/60.; + ay = ay/60.; + zRot = zRot/60.; + } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + } + else + { + throw std::runtime_error ("unknown cell"); + } + } + }; + + template + class OpPosition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + MWBase::Environment::get().getWorld()->moveObject(ptr, + *MWBase::Environment::get().getWorld()->getExterior(cx,cy),x,y,z); + float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees(); + float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees(); + if(ptr.getTypeName() == typeid(ESM::NPC).name())//some morrowind oddity + { + ax = ax/60.; + ay = ay/60.; + zRot = zRot/60.; + } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + } + }; + + template + class OpPlaceItemCell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + + MWWorld::CellStore* store = 0; + try + { + store = MWBase::Environment::get().getWorld()->getInterior(cellID); + } + catch(std::exception &e) + { + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + if(cell) + { + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + } + } + if(store) + { + ESM::Position pos; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; + pos.rot[0] = pos.rot[1] = 0; + pos.rot[2] = zRot; + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().mPos = pos; + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,pos); + } + else + { + throw std::runtime_error ("unknown cell"); + } + } + }; + + template + class OpPlaceItem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + MWWorld::CellStore* store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(store) + { + ESM::Position pos; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; + pos.rot[0] = pos.rot[1] = 0; + pos.rot[2] = zRot; + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().mPos = pos; + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,pos); + } + else + { + throw std::runtime_error ("unknown cell"); + } + } + }; + + template + class OpPlaceAtPc : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + Interpreter::Type_Float distance = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Integer direction = runtime[0].mInteger; + runtime.pop(); + + 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); + if(direction == 0) pos = pos + distance*rot.yAxis(); + else if(direction == 1) pos = pos - distance*rot.yAxis(); + else if(direction == 2) pos = pos - distance*rot.xAxis(); + else if(direction == 3) pos = pos + distance*rot.xAxis(); + else throw std::runtime_error ("direction must be 0,1,2 or 3"); + + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + MWWorld::CellStore* store = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().mPos = ipos; + ref.getPtr().getRefData().setCount(count); + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); + } + }; + + template + class OpPlaceAtMe : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr me = R()(runtime); + + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + Interpreter::Type_Float distance = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Integer direction = runtime[0].mInteger; + runtime.pop(); + + 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); + if(direction == 0) pos = pos + distance*rot.yAxis(); + else if(direction == 1) pos = pos - distance*rot.yAxis(); + else if(direction == 2) pos = pos - distance*rot.xAxis(); + else if(direction == 3) pos = pos + distance*rot.xAxis(); + else throw std::runtime_error ("direction must be 0,1,2 or 3"); + + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + MWWorld::CellStore* store = me.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().mPos = ipos; + ref.getPtr().getRefData().setCount(count); + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); + + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -149,8 +516,22 @@ namespace MWScript const int opcodeGetScaleExplicit = 0x2000169; const int opcodeGetAngle = 0x200016a; const int opcodeGetAngleExplicit = 0x200016b; - const int opcodeGetStartingAngle = 0x2000172; - const int opcodeGetStartingAngleExplicit = 0x2000173; + const int opcodeGetPos = 0x2000190; + const int opcodeGetPosExplicit = 0x2000191; + const int opcodeSetPos = 0x2000192; + const int opcodeSetPosExplicit = 0x2000193; + const int opcodeGetStartingPos = 0x2000194; + const int opcodeGetStartingPosExplicit = 0x2000195; + const int opcodePosition = 0x2000196; + const int opcodePositionExplicit = 0x2000197; + const int opcodePositionCell = 0x2000198; + const int opcodePositionCellExplicit = 0x2000199; + + const int opcodePlaceItemCell = 0x200019a; + const int opcodePlaceItem = 0x200019b; + const int opcodePlaceAtPc = 0x200019c; + const int opcodePlaceAtMe = 0x200019d; + const int opcodePlaceAtMeExplicit = 0x200019e; void registerExtensions (Compiler::Extensions& extensions) { @@ -158,7 +539,15 @@ namespace MWScript extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit); extensions.registerInstruction("setangle","cf",opcodeSetAngle,opcodeSetAngleExplicit); extensions.registerFunction("getangle",'f',"c",opcodeGetAngle,opcodeGetAngleExplicit); - extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit); + extensions.registerInstruction("setpos","cf",opcodeSetPos,opcodeSetPosExplicit); + extensions.registerFunction("getpos",'f',"c",opcodeGetPos,opcodeGetPosExplicit); + extensions.registerFunction("getstartingpos",'f',"c",opcodeGetStartingPos,opcodeGetStartingPosExplicit); + extensions.registerInstruction("position","ffff",opcodePosition,opcodePositionExplicit); + extensions.registerInstruction("positioncell","ffffc",opcodePositionCell,opcodePositionCellExplicit); + extensions.registerInstruction("placeitemcell","ccffff",opcodePlaceItemCell); + extensions.registerInstruction("placeitem","cffff",opcodePlaceItem); + extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); + extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -171,8 +560,21 @@ namespace MWScript interpreter.installSegment5(opcodeGetScaleExplicit,new OpGetScale); interpreter.installSegment5(opcodeGetAngle,new OpGetAngle); interpreter.installSegment5(opcodeGetAngleExplicit,new OpGetAngle); - interpreter.installSegment5(opcodeGetStartingAngle,new OpGetStartingAngle); - interpreter.installSegment5(opcodeGetStartingAngleExplicit,new OpGetStartingAngle); + interpreter.installSegment5(opcodeGetPos,new OpGetPos); + interpreter.installSegment5(opcodeGetPosExplicit,new OpGetPos); + interpreter.installSegment5(opcodeSetPos,new OpSetPos); + interpreter.installSegment5(opcodeSetPosExplicit,new OpSetPos); + interpreter.installSegment5(opcodeGetStartingPos,new OpGetStartingPos); + interpreter.installSegment5(opcodeGetStartingPosExplicit,new OpGetStartingPos); + interpreter.installSegment5(opcodePosition,new OpPosition); + interpreter.installSegment5(opcodePositionExplicit,new OpPosition); + interpreter.installSegment5(opcodePositionCell,new OpPositionCell); + interpreter.installSegment5(opcodePositionCellExplicit,new OpPositionCell); + interpreter.installSegment5(opcodePlaceItemCell,new OpPlaceItemCell); + interpreter.installSegment5(opcodePlaceItem,new OpPlaceItem); + interpreter.installSegment5(opcodePlaceAtPc,new OpPlaceAtPc); + interpreter.installSegment5(opcodePlaceAtMe,new OpPlaceAtMe); + interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); } } } diff --git a/apps/openmw/mwworld/actionread.cpp b/apps/openmw/mwworld/actionread.cpp index b108802f7..361da19f4 100644 --- a/apps/openmw/mwworld/actionread.cpp +++ b/apps/openmw/mwworld/actionread.cpp @@ -2,10 +2,18 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" +#include "../mwworld/class.hpp" + +#include "../mwmechanics/npcstats.hpp" #include "../mwgui/bookwindow.hpp" #include "../mwgui/scrollwindow.hpp" +#include + namespace MWWorld { ActionRead::ActionRead (const MWWorld::Ptr& object) : Action (false, object) @@ -26,5 +34,23 @@ namespace MWWorld MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Book); MWBase::Environment::get().getWindowManager()->getBookWindow()->open(getTarget()); } + + /* + // Skill gain from books + if (ref->base->data.skillID >= 0 && ref->base->data.skillID < ESM::Skill::Length) + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(player).getNpcStats (player); + MWWorld::LiveCellRef *playerRef = player.get(); + const ESM::Class *class_ = MWBase::Environment::get().getWorld()->getStore().classes.find ( + playerRef->base->cls); + + npcStats.increaseSkill (ref->base->data.skillID, *class_, true); + + /// \todo Remove skill from the book. Right now you can read as many times as you want + /// and the skill will still increase. + } + */ + } } diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index a427aa210..8fa1976ac 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -96,6 +96,10 @@ namespace MWWorld if(hasWater){ playerphysics->waterHeight = waterHeight; } + for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) + { + it->second->setCurrentWater(hasWater, waterHeight); + } } @@ -172,17 +176,20 @@ namespace MWWorld //set the DebugRenderingMode. To disable it,set it to 0 //eng->setDebugRenderingMode(1); - //set the walkdirection to 0 (no movement) for every actor) + //set the movement keys to 0 (no movement) for every actor) for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { OEngine::Physic::PhysicActor* act = it->second; - act->setWalkDirection(btVector3(0,0,0)); + act->setMovement(0,0,0); } + playerMove::playercmd& pm_ref = playerphysics->cmd; + pm_ref.rightmove = 0; pm_ref.forwardmove = 0; pm_ref.upmove = 0; + //playerphysics->ps.move_type = PM_NOCLIP; for (std::vector >::const_iterator iter (actors.begin()); @@ -193,10 +200,12 @@ namespace MWWorld playerphysics->ps.viewangles.x = Ogre::Radian(mPlayerData.pitch).valueDegrees(); + + playerphysics->ps.viewangles.y = Ogre::Radian(mPlayerData.yaw).valueDegrees() + 90; - pm_ref.rightmove = -iter->second.x; + pm_ref.rightmove = iter->second.x; pm_ref.forwardmove = -iter->second.y; pm_ref.upmove = iter->second.z; } @@ -208,16 +217,17 @@ namespace MWWorld const std::vector >& actors) { Pmove(playerphysics); + std::vector< std::pair > response; for(std::map::iterator it = mEngine->PhysicActorMap.begin(); it != mEngine->PhysicActorMap.end();it++) { - btVector3 newPos = it->second->getPosition(); - Ogre::Vector3 coord(newPos.x(), newPos.y(), newPos.z()); + Ogre::Vector3 coord = it->second->getPosition(); if(it->first == "player"){ - coord = playerphysics->ps.origin; + coord = playerphysics->ps.origin ; + } @@ -243,21 +253,15 @@ namespace MWWorld const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position) { handleToMesh[handle] = mesh; - OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale); + OEngine::Physic::RigidBody* body = mEngine->createAndAdjustRigidBody(mesh,handle,scale, position, rotation); mEngine->addRigidBody(body); - btTransform tr; - tr.setOrigin(btVector3(position.x,position.y,position.z)); - tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); - body->setWorldTransform(tr); } void PhysicsSystem::addActor (const std::string& handle, const std::string& mesh, - const Ogre::Vector3& position) + const Ogre::Vector3& position, float scale, const Ogre::Quaternion& rotation) { //TODO:optimize this. Searching the std::map isn't very efficient i think. - mEngine->addCharacter(handle); - OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle); - act->setPosition(btVector3(position.x,position.y,position.z)); + mEngine->addCharacter(handle, mesh, position, scale, rotation); } void PhysicsSystem::removeObject (const std::string& handle) @@ -268,15 +272,25 @@ namespace MWWorld mEngine->deleteRigidBody(handle); } - void PhysicsSystem::moveObject (const std::string& handle, const Ogre::Vector3& position) + void PhysicsSystem::moveObject (const std::string& handle, Ogre::SceneNode* node) { + Ogre::Vector3 position = node->getPosition(); if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) { // TODO very dirty hack to avoid crash during setup -> needs cleaning up to allow // start positions others than 0, 0, 0 - btTransform tr = body->getWorldTransform(); - tr.setOrigin(btVector3(position.x,position.y,position.z)); - body->setWorldTransform(tr); + + + if(dynamic_cast(body->getCollisionShape()) == NULL){ + btTransform tr = body->getWorldTransform(); + tr.setOrigin(btVector3(position.x,position.y,position.z)); + body->setWorldTransform(tr); + } + else{ + //For objects that contain a box shape. + //Do any such objects exist? Perhaps animated objects? + mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, position, node->getOrientation()); + } } if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { @@ -288,34 +302,45 @@ namespace MWWorld } else { - act->setPosition(btVector3(position.x,position.y,position.z)); + act->setPosition(position); } } } - void PhysicsSystem::rotateObject (const std::string& handle, const Ogre::Quaternion& rotation) + void PhysicsSystem::rotateObject (const std::string& handle, Ogre::SceneNode* node) { + Ogre::Quaternion rotation = node->getOrientation(); if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) { - act->setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + //Needs to be changed + act->setRotation(rotation); } if (OEngine::Physic::RigidBody* body = mEngine->getRigidBody(handle)) { - body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + if(dynamic_cast(body->getCollisionShape()) == NULL) + body->getWorldTransform().setRotation(btQuaternion(rotation.x, rotation.y, rotation.z, rotation.w)); + else + mEngine->boxAdjustExternal(handleToMesh[handle], body, node->getScale().x, node->getPosition(), rotation); } } - void PhysicsSystem::scaleObject (const std::string& handle, float scale) + void PhysicsSystem::scaleObject (const std::string& handle, Ogre::SceneNode* node) { if(handleToMesh.find(handle) != handleToMesh.end()) { - btTransform transform = mEngine->getRigidBody(handle)->getWorldTransform(); removeObject(handle); - Ogre::Quaternion quat = Ogre::Quaternion(transform.getRotation().getW(), transform.getRotation().getX(), transform.getRotation().getY(), transform.getRotation().getZ()); - Ogre::Vector3 vec = Ogre::Vector3(transform.getOrigin().getX(), transform.getOrigin().getY(), transform.getOrigin().getZ()); + float scale = node->getScale().x; + Ogre::Quaternion quat = node->getOrientation(); + Ogre::Vector3 vec = node->getPosition(); addObject(handle, handleToMesh[handle], quat, scale, vec); } + + if (OEngine::Physic::PhysicActor* act = mEngine->getCharacter(handle)) + { + float scale = node->getScale().x; + act->setScale(scale); + } } bool PhysicsSystem::toggleCollisionMode() @@ -335,8 +360,6 @@ namespace MWWorld if(cmode) { act->enableCollisions(false); - act->setGravity(0.); - act->setVerticalVelocity(0); mFreeFly = true; return false; } @@ -344,8 +367,6 @@ namespace MWWorld { mFreeFly = false; act->enableCollisions(true); - act->setGravity(4.); - act->setVerticalVelocity(0); return true; } } @@ -368,7 +389,7 @@ namespace MWWorld void PhysicsSystem::insertActorPhysics(const MWWorld::Ptr& ptr, const std::string model){ Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); - addActor (node->getName(), model, node->getPosition()); + addActor (node->getName(), model, node->getPosition(), node->getScale().x, node->getOrientation()); } bool PhysicsSystem::getObjectAABB(const MWWorld::Ptr &ptr, Ogre::Vector3 &min, Ogre::Vector3 &max) diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index c6b8199fa..1427060f6 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -24,7 +24,7 @@ namespace MWWorld const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position); void addActor (const std::string& handle, const std::string& mesh, - const Ogre::Vector3& position); + const Ogre::Vector3& position, float scale, const Ogre::Quaternion& rotation); void addHeightField (float* heights, int x, int y, float yoffset, @@ -34,11 +34,11 @@ namespace MWWorld void removeObject (const std::string& handle); - void moveObject (const std::string& handle, const Ogre::Vector3& position); + void moveObject (const std::string& handle, Ogre::SceneNode* node); - void rotateObject (const std::string& handle, const Ogre::Quaternion& rotation); + void rotateObject (const std::string& handle, Ogre::SceneNode* node); - void scaleObject (const std::string& handle, float scale); + void scaleObject (const std::string& handle, Ogre::SceneNode* node); bool toggleCollisionMode(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8cc859b7a..5e2ca4605 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -189,7 +189,9 @@ namespace MWWorld mPlayer = new MWWorld::Player (mStore.npcs.find ("player"), *this); mRendering->attachCameraTo(mPlayer->getPlayer()); - mPhysics->addActor (mPlayer->getPlayer().getRefData().getHandle(), "", Ogre::Vector3 (0, 0, 0)); + std::string playerCollisionFile = "meshes\\base_anim.nif"; //This is used to make a collision shape for our player + //We will need to support the 1st person file too in the future + mPhysics->addActor (mPlayer->getPlayer().getRefData().getHandle(), playerCollisionFile, Ogre::Vector3 (0, 0, 0), 1, Ogre::Quaternion::ZERO); // global variables mGlobalVariables = new Globals (mStore); @@ -450,6 +452,16 @@ namespace MWWorld mRendering->skySetDate (mGlobalVariables->getInt ("day"), month); } + int World::getDay() + { + return mGlobalVariables->getInt("day"); + } + + int World::getMonth() + { + return mGlobalVariables->getInt("month"); + } + TimeStamp World::getTimeStamp() const { return TimeStamp (mGlobalVariables->getFloat ("gamehour"), @@ -541,6 +553,16 @@ namespace MWWorld } } + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } + void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); @@ -550,11 +572,10 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; - if (*currCell != newCell) { if (isPlayer) { if (!newCell.isExterior()) { - changeToInteriorCell(newCell.cell->mName, pos); + changeToInteriorCell(toLower(newCell.cell->mName), pos); } else { int cellX = newCell.cell->mData.mX; int cellY = newCell.cell->mData.mY; @@ -594,7 +615,7 @@ namespace MWWorld } if (haveToMove) { mRendering->moveObject(ptr, vec); - mPhysics->moveObject(ptr.getRefData().getHandle(), vec); + mPhysics->moveObject (ptr.getRefData().getHandle(), ptr.getRefData().getBaseNode()); } } @@ -615,6 +636,8 @@ namespace MWWorld void World::moveObject (const Ptr& ptr, float x, float y, float z) { moveObjectImp(ptr, x, y, z); + + } void World::scaleObject (const Ptr& ptr, float scale) @@ -624,7 +647,7 @@ namespace MWWorld ptr.getCellRef().mScale = scale; //scale = scale/ptr.getRefData().getBaseNode()->getScale().x; ptr.getRefData().getBaseNode()->setScale(scale,scale,scale); - mPhysics->scaleObject( ptr.getRefData().getHandle(), scale ); + mPhysics->scaleObject( ptr.getRefData().getHandle(), ptr.getRefData().getBaseNode()); } void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust) @@ -633,18 +656,25 @@ namespace MWWorld rot.x = Ogre::Degree(x).valueRadians(); rot.y = Ogre::Degree(y).valueRadians(); rot.z = Ogre::Degree(z).valueRadians(); - + if (mRendering->rotateObject(ptr, rot, adjust)) { float *objRot = ptr.getRefData().getPosition().rot; objRot[0] = rot.x, objRot[1] = rot.y, objRot[2] = rot.z; + if (ptr.getRefData().getBaseNode() != 0) { mPhysics->rotateObject( ptr.getRefData().getHandle(), - ptr.getRefData().getBaseNode()->getOrientation() + ptr.getRefData().getBaseNode() ); } } + + } + + void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) + { + copyObjectToCell(ptr,Cell,pos); } void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const @@ -1223,8 +1253,37 @@ namespace MWWorld mRendering->renderPlayer(mPlayer->getPlayer()); } + void World::renderGlobalMap () + { + mRendering->renderGlobalMap (); + } + void World::setupExternalRendering (MWRender::ExternalRendering& rendering) { mRendering->setupExternalRendering (rendering); } + + int World::canRest () + { + Ptr::CellStore *currentCell = mWorldScene->getCurrentCell(); + + Ogre::Vector3 playerPos; + float* pos = mPlayer->getPlayer ().getRefData ().getPosition ().pos; + playerPos.x = pos[0]; + playerPos.y = pos[1]; + playerPos.z = pos[2]; + + std::pair hit = + mPhysics->castRay(playerPos, Ogre::Vector3(0,0,-1), 50); + bool isOnGround = (hit.first ? (hit.second.distance (playerPos) < 25) : false); + + if (!isOnGround || isUnderwater (*currentCell->cell, playerPos)) + return 2; + + if (currentCell->cell->mData.mFlags & ESM::Cell::NoSleep) + return 1; + + return 0; + + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 96e6ae3f8..5c5727905 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -179,6 +179,9 @@ namespace MWWorld virtual void setDay (int day); ///< Set in-game time day. + virtual int getDay(); + virtual int getMonth(); + virtual TimeStamp getTimeStamp() const; ///< Return current in-game time stamp. @@ -223,6 +226,9 @@ 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 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. + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const; ///< Convert cell numbers to position. @@ -307,8 +313,16 @@ namespace MWWorld } virtual void renderPlayer(); + virtual void renderGlobalMap(); virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); + + virtual int canRest(); + ///< check if the player is allowed to rest \n + /// 0 - yes \n + /// 1 - only waiting \n + /// 2 - player is underwater \n + /// 3 - enemies are nearby (not implemented) }; } diff --git a/components/esm/loadmgef.cpp b/components/esm/loadmgef.cpp index bcd1dfaf5..b36355d2a 100644 --- a/components/esm/loadmgef.cpp +++ b/components/esm/loadmgef.cpp @@ -3,8 +3,6 @@ #include "esm_reader.hpp" #include "esm_writer.hpp" -#include - namespace { const int NumberOfHardcodedFlags = 143; diff --git a/components/nifbullet/bullet_nif_loader.cpp b/components/nifbullet/bullet_nif_loader.cpp index 0fb758ea8..a70eb7629 100644 --- a/components/nifbullet/bullet_nif_loader.cpp +++ b/components/nifbullet/bullet_nif_loader.cpp @@ -72,6 +72,9 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) cShape = static_cast(resource); resourceName = cShape->getName(); cShape->collide = false; + mBoundingBox = NULL; + cShape->boxTranslation = Ogre::Vector3(0,0,0); + cShape->boxRotation = Ogre::Quaternion::IDENTITY; mTriMesh = new btTriangleMesh(); @@ -125,9 +128,14 @@ void ManualBulletShapeLoader::loadResource(Ogre::Resource *resource) delete m_meshInterface; } }; + if(mBoundingBox != NULL) + cShape->Shape = mBoundingBox; - currentShape = new TriangleMeshShape(mTriMesh,true); - cShape->Shape = currentShape; + else + { + currentShape = new TriangleMeshShape(mTriMesh,true); + cShape->Shape = currentShape; + } } bool ManualBulletShapeLoader::hasRootCollisionNode(Nif::Node* node) @@ -218,6 +226,17 @@ void ManualBulletShapeLoader::handleNode(Nif::Node *node, int flags, } + if(node->hasBounds) + { + + + btVector3 boxsize = getbtVector((node->boundXYZ)); + cShape->boxTranslation = node->boundPos; + cShape->boxRotation = node->boundRot; + + mBoundingBox = new btBoxShape(boxsize); + } + // For NiNodes, loop through children if (node->recType == Nif::RC_NiNode) diff --git a/components/nifbullet/bullet_nif_loader.hpp b/components/nifbullet/bullet_nif_loader.hpp index 88e1ab189..82ac227a0 100644 --- a/components/nifbullet/bullet_nif_loader.hpp +++ b/components/nifbullet/bullet_nif_loader.hpp @@ -102,8 +102,11 @@ private: std::string resourceName; std::string resourceGroup; + + BulletShape* cShape;//current shape btTriangleMesh *mTriMesh; + btBoxShape *mBoundingBox; btBvhTriangleMeshShape* currentShape;//the shape curently under construction }; diff --git a/files/materials/core.h b/files/materials/core.h index cba716777..e9577bbf3 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -1,3 +1,7 @@ +#define gammaCorrectRead(v) pow(v, float3(gammaCorrection,gammaCorrection,gammaCorrection)) +#define gammaCorrectOutput(v) pow(v, float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) + + #if SH_HLSL == 1 || SH_CG == 1 #define shTexture2D sampler2D diff --git a/files/materials/objects.shader b/files/materials/objects.shader index 8e5cbf76e..45f33774d 100644 --- a/files/materials/objects.shader +++ b/files/materials/objects.shader @@ -112,6 +112,8 @@ shUniform(float, far) @shAutoConstant(far, far_clip_distance) #endif + shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) + #if LIGHTING shInput(float3, normalPassthrough) shInput(float3, objSpacePositionPassthrough) @@ -173,7 +175,8 @@ SH_START_PROGRAM { shOutputColour(0) = shSample(diffuseMap, UV); - + shOutputColour(0).xyz = gammaCorrectRead(shOutputColour(0).xyz); + #if LIGHTING float3 normal = normalize(normalPassthrough); float3 lightDir; @@ -259,7 +262,7 @@ // regular fog only if fragment is above water if (worldPos.y > waterLevel) #endif - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif // prevent negative colour output (for example with negative lights) @@ -274,12 +277,11 @@ float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; + float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85)) *waterSunGradient * 0.5; float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - float3 waterext = float3(0.6, 0.9, 1.0);//water extinction + float3 watercolour = ( gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; @@ -292,6 +294,8 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater * waterEnabled); #endif + shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); + #if MRT shOutputColour(1) = float4(depthPassthrough / far,1,1,1); #endif diff --git a/files/materials/terrain.shader b/files/materials/terrain.shader index 7ef26d035..9183595e3 100644 --- a/files/materials/terrain.shader +++ b/files/materials/terrain.shader @@ -137,6 +137,8 @@ shSampler2D(normalMap) // global normal map + shUniform(float, gammaCorrection) @shSharedParameter(gammaCorrection, gammaCorrection) + @shForeach(@shPropertyString(num_blendmaps)) shSampler2D(blendMap@shIterator) @@ -247,9 +249,9 @@ #if IS_FIRST_PASS == 1 && @shIterator == 0 // first layer of first pass doesn't need a blend map - albedo = shSample(diffuseMap0, UV * 10).rgb; + albedo = gammaCorrectRead(shSample(diffuseMap0, UV * 10).rgb); #else - albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator)); + albedo = shLerp(albedo, gammaCorrectRead(shSample(diffuseMap@shIterator, UV * 10).rgb), blendValues@shPropertyString(blendmap_component_@shIterator)); #endif @shEndForeach @@ -336,7 +338,7 @@ // regular fog only if fragment is above water if (worldPos.y > waterLevel) #endif - shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue); + shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, gammaCorrectRead(fogColour), fogValue); #endif // prevent negative colour output (for example with negative lights) @@ -351,12 +353,12 @@ float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz)); waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0)); - float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5; + float3 waterSunColour = gammaCorrectRead(float3(0.0,1.0,0.85))*waterSunGradient * 0.5; float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0)); waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0); - float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0; - float3 waterext = float3(0.6, 0.9, 1.0);//water extinction + float3 watercolour = (gammaCorrectRead(float3(0.0078, 0.5176, 0.700))+waterSunColour)*waterGradient*2.0; + float3 waterext = gammaCorrectRead(float3(0.6, 0.9, 1.0));//water extinction watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT))); watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3; @@ -369,6 +371,8 @@ shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater); #endif + shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz); + #if MRT shOutputColour(1) = float4(depth / far,1,1,1); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index fdf447e69..ae8d3afbe 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -35,7 +35,7 @@ set(MYGUI_FILES openmw_dialogue_window.layout openmw_dialogue_window_skin.xml openmw_edit.skin.xml - openmw.font.xml + openmw_font.xml openmw_hud_box.skin.xml openmw_hud_energybar.skin.xml openmw_hud.layout @@ -51,7 +51,7 @@ set(MYGUI_FILES openmw_map_window.layout openmw_map_window_skin.xml openmw_messagebox.layout - openmw.pointer.xml + openmw_pointer.xml openmw_progress.skin.xml openmw_resources.xml openmw_scroll.layout @@ -72,6 +72,9 @@ set(MYGUI_FILES openmw_magicselection_dialog.layout openmw_spell_buying_window.layout openmw_loading_screen.layout + openmw_levelup_dialog.layout + openmw_wait_dialog.layout + openmw_wait_dialog_progressbar.layout smallbars.png VeraMono.ttf markers.png diff --git a/files/mygui/core.xml b/files/mygui/core.xml index e1fb1b5e2..ea1627875 100644 --- a/files/mygui/core.xml +++ b/files/mygui/core.xml @@ -4,8 +4,8 @@ - - + + diff --git a/files/mygui/openmw_alchemy_window.layout b/files/mygui/openmw_alchemy_window.layout index 458d24b2c..8471f69df 100644 --- a/files/mygui/openmw_alchemy_window.layout +++ b/files/mygui/openmw_alchemy_window.layout @@ -77,8 +77,9 @@ - - + + + diff --git a/files/mygui/openmw_chargen_birth.layout b/files/mygui/openmw_chargen_birth.layout index 5edec72d3..f4b8c518d 100644 --- a/files/mygui/openmw_chargen_birth.layout +++ b/files/mygui/openmw_chargen_birth.layout @@ -15,7 +15,9 @@ - + + + diff --git a/files/mygui/openmw_chargen_class.layout b/files/mygui/openmw_chargen_class.layout index baa36b24a..00e3793bc 100644 --- a/files/mygui/openmw_chargen_class.layout +++ b/files/mygui/openmw_chargen_class.layout @@ -61,7 +61,9 @@ - + + + diff --git a/files/mygui/openmw_chargen_create_class.layout b/files/mygui/openmw_chargen_create_class.layout index 5e08db6e5..54f73f221 100644 --- a/files/mygui/openmw_chargen_create_class.layout +++ b/files/mygui/openmw_chargen_create_class.layout @@ -59,7 +59,9 @@ - + + + diff --git a/files/mygui/openmw_chargen_generate_class_result.layout b/files/mygui/openmw_chargen_generate_class_result.layout index 65dbf016c..aa4a89d28 100644 --- a/files/mygui/openmw_chargen_generate_class_result.layout +++ b/files/mygui/openmw_chargen_generate_class_result.layout @@ -21,7 +21,9 @@ - + + + diff --git a/files/mygui/openmw_chargen_race.layout b/files/mygui/openmw_chargen_race.layout index b69073899..a9ec9905d 100644 --- a/files/mygui/openmw_chargen_race.layout +++ b/files/mygui/openmw_chargen_race.layout @@ -57,7 +57,10 @@ - + + + + diff --git a/files/mygui/openmw_chargen_review.layout b/files/mygui/openmw_chargen_review.layout index dbe7a4780..97e32cfe2 100644 --- a/files/mygui/openmw_chargen_review.layout +++ b/files/mygui/openmw_chargen_review.layout @@ -112,7 +112,9 @@ - + + + diff --git a/files/mygui/openmw_confirmation_dialog.layout b/files/mygui/openmw_confirmation_dialog.layout index fe7f7cbf6..46b477407 100644 --- a/files/mygui/openmw_confirmation_dialog.layout +++ b/files/mygui/openmw_confirmation_dialog.layout @@ -14,7 +14,9 @@ - + + + diff --git a/files/mygui/openmw_container_window.layout b/files/mygui/openmw_container_window.layout index 896566fdd..94e9458a5 100644 --- a/files/mygui/openmw_container_window.layout +++ b/files/mygui/openmw_container_window.layout @@ -12,7 +12,9 @@ - + + + diff --git a/files/mygui/openmw_count_window.layout b/files/mygui/openmw_count_window.layout index a021d7df9..5812ec7fd 100644 --- a/files/mygui/openmw_count_window.layout +++ b/files/mygui/openmw_count_window.layout @@ -22,7 +22,9 @@ - + + + diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw_font.xml similarity index 100% rename from files/mygui/openmw.font.xml rename to files/mygui/openmw_font.xml diff --git a/files/mygui/openmw_levelup_dialog.layout b/files/mygui/openmw_levelup_dialog.layout new file mode 100644 index 000000000..86e65e99a --- /dev/null +++ b/files/mygui/openmw_levelup_dialog.layout @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_map_window.layout b/files/mygui/openmw_map_window.layout index 8b64de22e..20cfbbd6e 100644 --- a/files/mygui/openmw_map_window.layout +++ b/files/mygui/openmw_map_window.layout @@ -3,21 +3,32 @@ - - - - - + - + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw.pointer.xml b/files/mygui/openmw_pointer.xml similarity index 100% rename from files/mygui/openmw.pointer.xml rename to files/mygui/openmw_pointer.xml diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 38d2786e5..2f9b5a67f 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -157,7 +157,7 @@ - + @@ -174,20 +174,37 @@ - + - + - + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_trade_window.layout b/files/mygui/openmw_trade_window.layout index 7de6c85e6..d38377f98 100644 --- a/files/mygui/openmw_trade_window.layout +++ b/files/mygui/openmw_trade_window.layout @@ -56,7 +56,9 @@ - + + + diff --git a/files/mygui/openmw_wait_dialog.layout b/files/mygui/openmw_wait_dialog.layout new file mode 100644 index 000000000..66e0ec22f --- /dev/null +++ b/files/mygui/openmw_wait_dialog.layout @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_wait_dialog_progressbar.layout b/files/mygui/openmw_wait_dialog_progressbar.layout new file mode 100644 index 000000000..93793fd8e --- /dev/null +++ b/files/mygui/openmw_wait_dialog_progressbar.layout @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 8fab98da2..1768b2f5e 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -24,6 +24,12 @@ antialiasing = none vsync = false +# opengl render to texture mode, valid options: +# PBuffer, FBO, Copy +opengl rtt mode = FBO + +gamma = 2.2 + [GUI] # 1 is fully opaque menu transparency = 0.84 diff --git a/libs/openengine/bullet/BulletShapeLoader.h b/libs/openengine/bullet/BulletShapeLoader.h index 316ee523c..8640fd54f 100644 --- a/libs/openengine/bullet/BulletShapeLoader.h +++ b/libs/openengine/bullet/BulletShapeLoader.h @@ -4,7 +4,7 @@ #include #include #include - +#include //For some reason, Ogre Singleton cannot be used in another namespace, that's why there is no namespace here. //But the risk of name collision seems pretty low here. @@ -31,6 +31,8 @@ public: virtual ~BulletShape(); btCollisionShape* Shape; + Ogre::Vector3 boxTranslation; + Ogre::Quaternion boxRotation; //this flag indicate if the shape is used for collision or if it's for raycasting only. bool collide; }; diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index a778aef3a..74352b358 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "pmove.h" #include #include "CMotionState.h" #include "OgreRoot.h" @@ -26,111 +27,139 @@ namespace Physic COL_RAYCASTING = BIT(3) }; - PhysicActor::PhysicActor(std::string name) + PhysicActor::PhysicActor(std::string name, std::string mesh, PhysicEngine* engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale): + mName(name), mEngine(engine), mMesh(mesh), mBoxScaledTranslation(0,0,0), mBoxRotationInverse(0,0,0,0), mBody(0), collisionMode(false), mBoxRotation(0,0,0,0) { - mName = name; - - // The capsule is at the origin - btTransform transform; - transform.setIdentity(); - - // External capsule - externalGhostObject = new PairCachingGhostObject(name); - externalGhostObject->setWorldTransform( transform ); - - btScalar externalCapsuleHeight = 120; - btScalar externalCapsuleWidth = 19; - - externalCollisionShape = new btCapsuleShapeZ( externalCapsuleWidth, externalCapsuleHeight ); - externalCollisionShape->setMargin( 0.1 ); - - externalGhostObject->setCollisionShape( externalCollisionShape ); - externalGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT ); - - // Internal capsule - internalGhostObject = new PairCachingGhostObject(name); - internalGhostObject->setWorldTransform( transform ); - //internalGhostObject->getBroadphaseHandle()->s - btScalar internalCapsuleHeight = 110; - btScalar internalCapsuleWidth = 17; - - internalCollisionShape = new btCapsuleShapeZ( internalCapsuleWidth, internalCapsuleHeight ); - internalCollisionShape->setMargin( 0.1 ); - - internalGhostObject->setCollisionShape( internalCollisionShape ); - internalGhostObject->setCollisionFlags( btCollisionObject::CF_CHARACTER_OBJECT ); - - mCharacter = new btKinematicCharacterController( externalGhostObject,internalGhostObject,btScalar( 40 ),1,4,20,9.8,0.2 ); - mCharacter->setUpAxis(btKinematicCharacterController::Z_AXIS); - mCharacter->setUseGhostSweepTest(false); - - mCharacter->mCollision = false; - setGravity(0); - - mTranslation = btVector3(0,0,70); + mBody = mEngine->createAndAdjustRigidBody(mMesh, mName, scale, position, rotation, &mBoxScaledTranslation, &mBoxRotation); + Ogre::Quaternion inverse = mBoxRotation.Inverse(); + mBoxRotationInverse = btQuaternion(inverse.x, inverse.y, inverse.z,inverse.w); + mEngine->addRigidBody(mBody, false); //Add rigid body to dynamics world, but do not add to object map + pmove = new playerMove; + pmove->mEngine = mEngine; + btBoxShape* box = static_cast (mBody->getCollisionShape()); + if(box != NULL){ + btVector3 size = box->getHalfExtentsWithMargin(); + Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); + pmove->ps.halfExtents = halfExtents; + } } PhysicActor::~PhysicActor() { - delete mCharacter; - delete internalGhostObject; - delete internalCollisionShape; - delete externalGhostObject; - delete externalCollisionShape; + if(mBody){ + mEngine->dynamicsWorld->removeRigidBody(mBody); + delete mBody; + } + delete pmove; + } + + void PhysicActor::setCurrentWater(bool hasWater, int waterHeight){ + pmove->hasWater = hasWater; + if(hasWater){ + pmove->waterHeight = waterHeight; + } } void PhysicActor::setGravity(float gravity) { - mCharacter->setGravity(gravity); - //mCharacter-> + pmove->ps.gravity = gravity; + } + + void PhysicActor::setSpeed(float speed) + { + pmove->ps.speed = speed; } void PhysicActor::enableCollisions(bool collision) { - mCharacter->mCollision = collision; + collisionMode = collision; + if(collisionMode) + pmove->ps.move_type=PM_NORMAL; + else + pmove->ps.move_type=PM_NOCLIP; } - void PhysicActor::setVerticalVelocity(float z) + void PhysicActor::setJumpVelocity(float velocity) { - mCharacter->setVerticalVelocity(z); + pmove->ps.jump_velocity = velocity; } bool PhysicActor::getCollisionMode() { - return mCharacter->mCollision; + return collisionMode; } - void PhysicActor::setWalkDirection(const btVector3& mvt) + void PhysicActor::setMovement(signed char rightmove, signed char forwardmove, signed char upmove) { - mCharacter->setWalkDirection( mvt ); + playerMove::playercmd& pm_ref = pmove->cmd; + pm_ref.rightmove = rightmove; + pm_ref.forwardmove = forwardmove; + pm_ref.upmove = upmove; } - void PhysicActor::Rotate(const btQuaternion& quat) - { - externalGhostObject->getWorldTransform().setRotation( externalGhostObject->getWorldTransform().getRotation() * quat ); - internalGhostObject->getWorldTransform().setRotation( internalGhostObject->getWorldTransform().getRotation() * quat ); + void PhysicActor::setPmoveViewAngles(float pitch, float yaw, float roll){ + pmove->ps.viewangles.x = pitch; + pmove->ps.viewangles.y = yaw; + pmove->ps.viewangles.z = roll; } - void PhysicActor::setRotation(const btQuaternion& quat) + + + void PhysicActor::setRotation(const Ogre::Quaternion quat) { - externalGhostObject->getWorldTransform().setRotation( quat ); - internalGhostObject->getWorldTransform().setRotation( quat ); + if(!quat.equals(getRotation(), Ogre::Radian(0))){ + mEngine->adjustRigidBody(mBody, getPosition(), quat, mBoxScaledTranslation, mBoxRotation); + } } - btVector3 PhysicActor::getPosition(void) + Ogre::Vector3 PhysicActor::getPosition() { - return internalGhostObject->getWorldTransform().getOrigin() -mTranslation; + 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()); + Ogre::Vector3 transrot = rotation * mBoxScaledTranslation; + Ogre::Vector3 visualPosition = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()) - transrot; + return visualPosition; } - btQuaternion PhysicActor::getRotation(void) + Ogre::Quaternion PhysicActor::getRotation() { - return internalGhostObject->getWorldTransform().getRotation(); + btQuaternion quat = mBody->getWorldTransform().getRotation() * mBoxRotationInverse; + return Ogre::Quaternion(quat.getW(), quat.getX(), quat.getY(), quat.getZ()); } - void PhysicActor::setPosition(const btVector3& pos) + void PhysicActor::setPosition(const Ogre::Vector3 pos) { - internalGhostObject->getWorldTransform().setOrigin(pos+mTranslation); - externalGhostObject->getWorldTransform().setOrigin(pos+mTranslation); + mEngine->adjustRigidBody(mBody, pos, getRotation(), mBoxScaledTranslation, mBoxRotation); + btVector3 vec = mBody->getWorldTransform().getOrigin(); + pmove->ps.origin = Ogre::Vector3(vec.getX(), vec.getY(), vec.getZ()); + } + + 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); + delete mBody; + } + //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 + btBoxShape* box = static_cast (mBody->getCollisionShape()); + if(box != NULL){ + btVector3 size = box->getHalfExtentsWithMargin(); + Ogre::Vector3 halfExtents = Ogre::Vector3(size.getX(), size.getY(), size.getZ()); + pmove->ps.halfExtents = halfExtents; + } + } + + void PhysicActor::runPmove(){ + Pmove(pmove); + Ogre::Vector3 newpos = pmove->ps.origin; + mBody->getWorldTransform().setOrigin(btVector3(newpos.x, newpos.y, newpos.z)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -230,8 +259,8 @@ namespace Physic delete hf_it->second.mBody; } - RigidBodyContainer::iterator rb_it = RigidBodyMap.begin(); - for (; rb_it != RigidBodyMap.end(); ++rb_it) + RigidBodyContainer::iterator rb_it = ObjectMap.begin(); + for (; rb_it != ObjectMap.end(); ++rb_it) { if (rb_it->second != NULL) { @@ -247,9 +276,7 @@ namespace Physic { if (pa_it->second != NULL) { - dynamicsWorld->removeCollisionObject(pa_it->second->externalGhostObject); - dynamicsWorld->removeCollisionObject(pa_it->second->internalGhostObject); - dynamicsWorld->removeAction(pa_it->second->mCharacter); + delete pa_it->second; pa_it->second = NULL; @@ -332,18 +359,42 @@ namespace Physic mHeightFieldMap.erase(name); } - RigidBody* PhysicEngine::createRigidBody(std::string mesh,std::string name,float scale) - { + void PhysicEngine::adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, + Ogre::Vector3 scaledBoxTranslation, Ogre::Quaternion boxRotation){ + btTransform tr; + rotation = rotation * boxRotation; + Ogre::Vector3 transrot = rotation * scaledBoxTranslation; + Ogre::Vector3 newPosition = transrot + position; + + tr.setOrigin(btVector3(newPosition.x, newPosition.y, newPosition.z)); + tr.setRotation(btQuaternion(rotation.x,rotation.y,rotation.z,rotation.w)); + body->setWorldTransform(tr); + } + void PhysicEngine::boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation){ std::string sid = (boost::format("%07.3f") % scale).str(); std::string outputstring = mesh + sid; //std::cout << "The string" << outputstring << "\n"; + //get the shape from the .nif + mShapeLoader->load(outputstring,"General"); + BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); + BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); + + adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); + } + + RigidBody* PhysicEngine::createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + Ogre::Vector3* scaledBoxTranslation, Ogre::Quaternion* boxRotation) + { + std::string sid = (boost::format("%07.3f") % scale).str(); + std::string outputstring = mesh + sid; + //get the shape from the .nif mShapeLoader->load(outputstring,"General"); BulletShapeManager::getSingletonPtr()->load(outputstring,"General"); BulletShapePtr shape = BulletShapeManager::getSingleton().getByName(outputstring,"General"); shape->Shape->setLocalScaling( btVector3(scale,scale,scale)); - //btScaledBvhTriangleMeshShape* scaled = new btScaledBvhTriangleMeshShape(dynamic_cast (shape->Shape), btVector3(scale,scale,scale)); + //create the motionState CMotionState* newMotionState = new CMotionState(this,name); @@ -352,11 +403,19 @@ namespace Physic btRigidBody::btRigidBodyConstructionInfo CI = btRigidBody::btRigidBodyConstructionInfo(0,newMotionState,shape->Shape); RigidBody* body = new RigidBody(CI,name); body->collide = shape->collide; + + if(scaledBoxTranslation != 0) + *scaledBoxTranslation = shape->boxTranslation * scale; + if(boxRotation != 0) + *boxRotation = shape->boxRotation; + + adjustRigidBody(body, position, rotation, shape->boxTranslation * scale, shape->boxRotation); + return body; } - void PhysicEngine::addRigidBody(RigidBody* body) + void PhysicEngine::addRigidBody(RigidBody* body, bool addToMap) { if(body) { @@ -369,21 +428,23 @@ namespace Physic dynamicsWorld->addRigidBody(body,COL_RAYCASTING,COL_RAYCASTING|COL_WORLD); } body->setActivationState(DISABLE_DEACTIVATION); - RigidBody* oldBody = RigidBodyMap[body->mName]; - if (oldBody != NULL) - { - dynamicsWorld->removeRigidBody(oldBody); - delete oldBody; - } + if(addToMap){ + RigidBody* oldBody = ObjectMap[body->mName]; + if (oldBody != NULL) + { + dynamicsWorld->removeRigidBody(oldBody); + delete oldBody; + } - RigidBodyMap[body->mName] = body; + ObjectMap[body->mName] = body; + } } } void PhysicEngine::removeRigidBody(std::string name) { - RigidBodyContainer::iterator it = RigidBodyMap.find(name); - if (it != RigidBodyMap.end() ) + RigidBodyContainer::iterator it = ObjectMap.find(name); + if (it != ObjectMap.end() ) { RigidBody* body = it->second; if(body != NULL) @@ -402,8 +463,8 @@ namespace Physic void PhysicEngine::deleteRigidBody(std::string name) { - RigidBodyContainer::iterator it = RigidBodyMap.find(name); - if (it != RigidBodyMap.end() ) + RigidBodyContainer::iterator it = ObjectMap.find(name); + if (it != ObjectMap.end() ) { RigidBody* body = it->second; //btScaledBvhTriangleMeshShape* scaled = dynamic_cast (body->getCollisionShape()); @@ -416,16 +477,16 @@ namespace Physic { delete scaled; }*/ - RigidBodyMap.erase(it); + ObjectMap.erase(it); } } RigidBody* PhysicEngine::getRigidBody(std::string name) { - RigidBodyContainer::iterator it = RigidBodyMap.find(name); - if (it != RigidBodyMap.end() ) + RigidBodyContainer::iterator it = ObjectMap.find(name); + if (it != ObjectMap.end() ) { - RigidBody* body = RigidBodyMap[name]; + RigidBody* body = ObjectMap[name]; return body; } else @@ -443,16 +504,17 @@ namespace Physic } } - void PhysicEngine::addCharacter(std::string name) + void PhysicEngine::addCharacter(std::string name, std::string mesh, + Ogre::Vector3 position, float scale, Ogre::Quaternion rotation) { // Remove character with given name, so we don't make memory // leak when character would be added twice removeCharacter(name); - PhysicActor* newActor = new PhysicActor(name); - dynamicsWorld->addCollisionObject( newActor->externalGhostObject, COL_ACTOR_EXTERNAL, COL_WORLD |COL_ACTOR_EXTERNAL ); - dynamicsWorld->addCollisionObject( newActor->internalGhostObject, COL_ACTOR_INTERNAL, COL_WORLD |COL_ACTOR_INTERNAL ); - dynamicsWorld->addAction( newActor->mCharacter ); + PhysicActor* newActor = new PhysicActor(name, mesh, this, position, rotation, scale); + + + //dynamicsWorld->addAction( newActor->mCharacter ); PhysicActorMap[name] = newActor; } @@ -465,25 +527,11 @@ namespace Physic PhysicActor* act = it->second; if(act != NULL) { - /*broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->externalGhostObject->getBroadphaseHandle(),dispatcher); - broadphase->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->internalGhostObject->getBroadphaseHandle(),dispatcher); - PhysicActorContainer::iterator it2 = PhysicActorMap.begin(); - for(;it2!=PhysicActorMap.end();it++) - { - it->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->externalGhostObject->getBroadphaseHandle(),dispatcher); - it->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->externalGhostObject->getBroadphaseHandle(),dispatcher); - it->second->internalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->internalGhostObject->getBroadphaseHandle(),dispatcher); - it->second->externalGhostObject->getOverlappingPairCache()->removeOverlappingPairsContainingProxy(act->internalGhostObject->getBroadphaseHandle(),dispatcher); - }*/ - //act->externalGhostObject-> - dynamicsWorld->removeCollisionObject(act->externalGhostObject); - dynamicsWorld->removeCollisionObject(act->internalGhostObject); - dynamicsWorld->removeAction(act->mCharacter); + delete act; } PhysicActorMap.erase(it); } - //std::cout << "ok"; } PhysicActor* PhysicEngine::getCharacter(std::string name) diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 9ae8e7607..e4e71706f 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -9,14 +9,16 @@ #include "BulletShapeLoader.h" #include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h" + + class btRigidBody; class btBroadphaseInterface; class btDefaultCollisionConfiguration; class btSequentialImpulseConstraintSolver; class btCollisionDispatcher; class btDiscreteDynamicsWorld; -class btKinematicCharacterController; class btHeightfieldTerrainShape; +struct playerMove; namespace BtOgre { @@ -28,11 +30,14 @@ namespace MWWorld class World; } + namespace OEngine { namespace Physic { class CMotionState; struct PhysicEvent; + class PhysicEngine; + class RigidBody; /** *This is just used to be able to name objects. @@ -50,55 +55,88 @@ namespace Physic }; /** - * A physic Actor use a modifed KinematicCharacterController taken in the bullet forum. + * A physic actor uses a rigid body based on box shapes. + * Pmove is used to move the physic actor around the dynamic world. */ class PhysicActor { public: - PhysicActor(std::string name); + PhysicActor(std::string name, std::string mesh, PhysicEngine *engine, Ogre::Vector3 position, Ogre::Quaternion rotation, float scale); ~PhysicActor(); + void setCurrentWater(bool hasWater, int waterHeight); + /** - * This function set the walkDirection. This is not relative to the actor orientation. - * I think it's also needed to take time into account. A typical call should look like this: - * setWalkDirection( mvt * orientation * dt) + * This function sets the movement keys for pmove */ - void setWalkDirection(const btVector3& mvt); + void setMovement(signed char rightmove, signed char forwardmove, signed char upmove); - void Rotate(const btQuaternion& quat); - - void setRotation(const btQuaternion& quat); + /** + * This adjusts the rotation of a PhysicActor + * If we have any problems with this (getting stuck in pmove) we should change it + * from setting the visual orientation to setting the orientation of the rigid body directly. + */ + void setRotation(const Ogre::Quaternion quat); void setGravity(float gravity); - void setVerticalVelocity(float z); + void setSpeed(float speed); + + void setJumpVelocity(float velocity); void enableCollisions(bool collision); bool getCollisionMode(); - btVector3 getPosition(void); - - btQuaternion getRotation(void); - - void setPosition(const btVector3& pos); - - btKinematicCharacterController* mCharacter; - - PairCachingGhostObject* internalGhostObject; - btCollisionShape* internalCollisionShape; - - PairCachingGhostObject* externalGhostObject; - btCollisionShape* externalCollisionShape; - - std::string mName; + /** + * This returns the visual position of the PhysicActor (used to position a scenenode). + * Note - this is different from the position of the contained mBody. + */ + Ogre::Vector3 getPosition(); /** - *NPC scenenode is located on there feet, and you can't simply translate a btShape, so this vector is used - *each time get/setposition is called. - */ - btVector3 mTranslation; + * Returns the visual orientation of the PhysicActor + */ + Ogre::Quaternion getRotation(); + + /** + * Sets the position of mBody from a visual position input. + * For most cases this should not be used. We should instead let pmove move the PhysicActor around for us + */ + void setPosition(const Ogre::Vector3 pos); + + /** + * Sets the view angles for pmove directly. + * Remember, add 90 for yaw. Set roll to 0. + */ + void setPmoveViewAngles(float pitch, float yaw, float roll); + + /** + * Sets the scale of the PhysicActor + */ + void setScale(float scale); + + /** + * Runs pmove for this PhysicActor + */ + void runPmove(); + + + + + private: + + OEngine::Physic::RigidBody* mBody; + Ogre::Vector3 mBoxScaledTranslation; + btQuaternion mBoxRotationInverse; + Ogre::Quaternion mBoxRotation; + bool collisionMode; + std::string mMesh; + PhysicEngine* mEngine; + std::string mName; + playerMove* pmove; + }; /** @@ -143,11 +181,22 @@ namespace Physic ~PhysicEngine(); /** - * Create a RigidBody.It does not add it to the simulation, but it does add it to the rigidBody Map, - * so you can get it with the getRigidBody function. + * Creates a RigidBody. It does not add it to the simulation. + * After created, the body is set to the correct rotation, position, and scale */ - RigidBody* createRigidBody(std::string mesh,std::string name,float scale); + RigidBody* createAndAdjustRigidBody(std::string mesh,std::string name,float scale, Ogre::Vector3 position, Ogre::Quaternion rotation, + Ogre::Vector3* scaledBoxTranslation = 0, Ogre::Quaternion* boxRotation = 0); + /** + * Adjusts a rigid body to the right position and rotation + */ + + void adjustRigidBody(RigidBody* body, Ogre::Vector3 position, Ogre::Quaternion rotation, + Ogre::Vector3 scaledBoxTranslation = Ogre::Vector3::ZERO, Ogre::Quaternion boxRotation = Ogre::Quaternion::IDENTITY); + /** + Mainly used to (but not limited to) adjust rigid bodies based on box shapes to the right position and rotation. + */ + void boxAdjustExternal(std::string mesh, RigidBody* body, float scale, Ogre::Vector3 position, Ogre::Quaternion rotation); /** * Add a HeightField to the simulation */ @@ -163,7 +212,7 @@ namespace Physic /** * Add a RigidBody to the simulation */ - void addRigidBody(RigidBody* body); + void addRigidBody(RigidBody* body, bool addToMap = true); /** * Remove a RigidBody from the simulation. It does not delete it, and does not remove it from the RigidBodyMap. @@ -184,7 +233,8 @@ namespace Physic /** * Create and add a character to the scene, and add it to the ActorMap. */ - void addCharacter(std::string name); + void addCharacter(std::string name, std::string mesh, + Ogre::Vector3 position, float scale, Ogre::Quaternion rotation); /** * Remove a character from the scene. TODO:delete it! for now, a small memory leak^^ done? @@ -254,7 +304,7 @@ namespace Physic HeightFieldContainer mHeightFieldMap; typedef std::map RigidBodyContainer; - RigidBodyContainer RigidBodyMap; + RigidBodyContainer ObjectMap; typedef std::map PhysicActorContainer; PhysicActorContainer PhysicActorMap; @@ -263,6 +313,7 @@ namespace Physic BtOgre::DebugDrawer* mDebugDrawer; bool isDebugCreated; bool mDebugActive; + }; diff --git a/libs/openengine/bullet/pmove.cpp b/libs/openengine/bullet/pmove.cpp index e13e9e6c0..645abf205 100644 --- a/libs/openengine/bullet/pmove.cpp +++ b/libs/openengine/bullet/pmove.cpp @@ -231,7 +231,7 @@ bool PM_SlideMove( bool gravity ) // see if we can make it there //pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemaskg); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&(end), *(const D3DXVECTOR3* const)&(pm->ps.velocity), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, end, halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(&trace, pm->ps.origin, end, pm->ps.halfExtents, Ogre::Math::DegreesToRadians (pm->ps.viewangles.y), pm->isInterior, pm->mEngine); if (trace.allsolid) { @@ -301,7 +301,7 @@ bool PM_SlideMove( bool gravity ) if(planes[i].x >= .70) { - pm->ps.velocity = Ogre::Vector3(0,0,0); + pm->ps.velocity.z = 0; return true; } // see how hard we are hitting things @@ -449,7 +449,7 @@ int PM_StepSlideMove( bool gravity ) //pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, start_o, down, , 0, pml.scene); //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, down, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(&trace, down, start_o, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); // up = vec3(0, 0, 1) //VectorSet(up, 0, 0, 1); @@ -479,7 +479,7 @@ int PM_StepSlideMove( bool gravity ) // test the player position if they were a stepheight higher //pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&start_o, *(const D3DXVECTOR3* const)&up, D3DXVECTOR3(0.0f, STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, start_o, up, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(&trace, start_o, up, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); if ( trace.allsolid ) { //if ( pm->debugLevel ) @@ -510,7 +510,7 @@ int PM_StepSlideMove( bool gravity ) //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&down, D3DXVECTOR3(0.0f, -STEPSIZE, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, down, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(&trace, pm->ps.origin, down, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); if ( !trace.allsolid ) //VectorCopy (trace.endpos, pm->ps->origin); pm->ps.origin = trace.endpos; @@ -527,7 +527,7 @@ int PM_StepSlideMove( bool gravity ) delta = pm->ps.origin.z - start_o.z; if ( delta > 2 ) { - pm->ps.counter = 5; + pm->ps.counter = 10; /* if (gravity) @@ -657,10 +657,11 @@ static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel // int i; float addspeed, accelspeed, currentspeed; + // currentspeed = pm->ps->velocity dot wishdir //currentspeed = DotProduct (pm->ps->velocity, wishdir); currentspeed = pm->ps.velocity.dotProduct(wishdir); - + addspeed = wishspeed - currentspeed; if (addspeed <= 0) return; @@ -675,6 +676,8 @@ static void PM_Accelerate( Ogre::Vector3& wishdir, float wishspeed, float accel //for (i=0 ; i<3 ; i++) //pm->ps->velocity[i] += accelspeed * wishdir[i]; pm->ps.velocity += (wishdir * accelspeed); + //pm->ps.velocity = wishdir * wishspeed; //New, for instant acceleration + } static bool PM_CheckJump(void) @@ -701,7 +704,7 @@ static bool PM_CheckJump(void) //pm->ps->pm_flags |= PMF_JUMP_HELD; pm->ps.groundEntityNum = ENTITYNUM_NONE; - pm->ps.velocity.z = JUMP_VELOCITY; + pm->ps.velocity.z = pm->ps.jump_velocity; pm->ps.bSnap = false; //PM_AddEvent( EV_JUMP ); @@ -899,7 +902,7 @@ static void PM_WalkMove( playerMove* const pmove ) if (pmove->hasWater ) { const float waterHeight = pmove->waterHeight; - const float waterSoundStepHeight = waterHeight + halfExtents.y; + const float waterSoundStepHeight = waterHeight + pm->ps.halfExtents.y; if (pmove->ps.origin.y < waterSoundStepHeight) step_underwater = true; } @@ -1179,7 +1182,7 @@ void PM_GroundTraceMissed() //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -64.0f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); //It hit the ground below if ( trace.fraction < 1.0 && pm->ps.origin.z > trace.endpos.z) { @@ -1225,7 +1228,7 @@ static bool PM_CorrectAllSolid(traceResults* const trace) //pm->trace (trace, point, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(trace, *(const D3DXVECTOR3* const)&point, *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, 0.0f, 0.0f), 0, pml.traceObj); - newtrace(trace, point, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(trace, point, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); if ( !trace->allsolid ) { @@ -1237,7 +1240,7 @@ static bool PM_CorrectAllSolid(traceResults* const trace) //pm->trace (trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); pml.groundTrace = *trace; return true; } @@ -1338,7 +1341,7 @@ static void PM_CrashLand( void ) { const float waterHeight = pm->waterHeight; - const float waterHeightSplash = waterHeight + halfExtents.y; + const float waterHeightSplash = waterHeight + pm->ps.halfExtents.y; if (pm->ps.origin.z < waterHeightSplash) { splashSound = true; @@ -1413,7 +1416,7 @@ static void PM_GroundTrace( void ) //pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask); //tracefunc(&trace, *(const D3DXVECTOR3* const)&(pm->ps.origin), *(const D3DXVECTOR3* const)&point, D3DXVECTOR3(0.0f, -0.25f, 0.0f), 0, pml.traceObj); - newtrace(&trace, pm->ps.origin, point, halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); + newtrace(&trace, pm->ps.origin, point, pm->ps.halfExtents, Ogre::Math::DegreesToRadians(pm->ps.viewangles.y), pm->isInterior, pm->mEngine); pml.groundTrace = trace; // do something corrective if the trace starts in a solid... diff --git a/libs/openengine/bullet/pmove.h b/libs/openengine/bullet/pmove.h index aea63d1db..fa303184e 100644 --- a/libs/openengine/bullet/pmove.h +++ b/libs/openengine/bullet/pmove.h @@ -23,7 +23,7 @@ Quake 3 Arena is copyright (C) 1999-2005 Id Software, Inc. extern SceneInstance* global_lastscene; #endif*/ -static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); +static const Ogre::Vector3 halfExtentsDefault(14.64f * 2, 14.24f * 2, 33.25f * 2); #define MAX_CLIP_PLANES 5 #define OVERCLIP 1.001f @@ -42,7 +42,6 @@ static const Ogre::Vector3 halfExtents(14.64f * 2, 14.24f * 2, 33.25f * 2); #define ENTITYNUM_NONE (MAX_GENTITIES - 1) #define ENTITYNUM_WORLD (MAX_GENTITIES - 2) #define MIN_WALK_NORMAL .7f // can't walk on very steep slopes -#define JUMP_VELOCITY (270) #define PS_PMOVEFRAMECOUNTBITS 6 #define MINS_Z -24 #define DEFAULT_VIEWHEIGHT 26 @@ -90,9 +89,9 @@ struct playerMove { struct playerStruct { - playerStruct() : gravity(800.0f), speed(480.0f), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1) + playerStruct() : gravity(800.0f), speed(480.0f), jump_velocity(270), pmove_framecount(20), groundEntityNum(ENTITYNUM_NONE), commandTime(40), move_type(PM_NOCLIP), pm_time(0), snappingImplemented(true), bSnap(false), counter(-1), halfExtents(halfExtentsDefault) { - origin = Ogre::Vector3(733.164f,900.0f, 839.432f); + origin = Ogre::Vector3(0.0f, 0.0f, 0.0f); velocity = Ogre::Vector3(0.0f, 0.0f, 0.0f); viewangles = Ogre::Vector3(0.0f, 0.0f, 0.0f); @@ -117,11 +116,13 @@ struct playerMove Ogre::Vector3 velocity; Ogre::Vector3 origin; + Ogre::Vector3 halfExtents; bool bSnap; bool snappingImplemented; int counter; float gravity; // default = 800 float speed; // default = 320 + float jump_velocity; //default = 270 int commandTime; // the time at which this command was issued (in milliseconds) diff --git a/libs/openengine/bullet/trace.cpp b/libs/openengine/bullet/trace.cpp index 89d654e6a..03ed4ffb1 100644 --- a/libs/openengine/bullet/trace.cpp +++ b/libs/openengine/bullet/trace.cpp @@ -13,18 +13,22 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogre::Vector3& end, const Ogre::Vector3& BBHalfExtents, const float rotation, bool isInterior, OEngine::Physic::PhysicEngine* enginePass) //Traceobj was a Aedra Object { - + static float lastyaw = 0.0f; + static float lastpitch = 0.0f; //if (!traceobj) // return; //if (!traceobj->incellptr) // return; + const Ogre::Vector3 rayDir = end - start; + + + - // Nudge starting point backwards - //const Position3D nudgestart = start + (rayDir * -0.1f); // by 10% (isn't that too much?) - //const Position3D nudgestart = start; + + NewPhysTraceResults out; //std::cout << "Starting trace\n"; @@ -32,7 +36,7 @@ void newtrace(traceResults* const results, const Ogre::Vector3& start, const Ogr //Ogre::Vector3 endReplace = startReplace; //endReplace.z -= .25; - const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0, rotation), isInterior, enginePass); + const bool hasHit = NewPhysicsTrace(&out, start, end, BBHalfExtents, Ogre::Vector3(0.0f, 0.0f, 0.0f), isInterior, enginePass); if (out.fraction < 0.001f) results->startsolid = true; @@ -95,13 +99,14 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& //if(enginePass->dynamicsWorld->getCollisionObjectArray().at(60)->getCollisionShape()->isConvex()) // std::cout << "It's convex\n"; - + const btVector3 btstart(start.x, start.y, start.z + BBHalfExtents.z); const btVector3 btend(end.x, end.y, end.z + BBHalfExtents.z); const btQuaternion btrot(rotation.y, rotation.x, rotation.z); //y, x, z - const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); + const btBoxShape newshape(btVector3(BBHalfExtents.x, BBHalfExtents.y, BBHalfExtents.z)); + //const btCapsuleShapeZ newshape(BBHalfExtents.x, BBHalfExtents.z * 2 - BBHalfExtents.x * 2); const btTransform from(btrot, btstart); const btTransform to(btrot, btend); @@ -176,7 +181,8 @@ const bool NewPhysicsTrace(NewPhysTraceResults* const out, const Ogre::Vector3& if (!TestPointAgainstAabb2(aabbMin, aabbMax, *(const btVector3* const)&(start) ) ) { //We're solid - out->startSolid = true; + //THIS NEEDS TO BE TURNED OFF IF WE WANT FALLING IN EXTERIORS TO WORK CORRECTLY!!!!!!! + //out->startSolid = true; } } } diff --git a/libs/openengine/bullet/trace.h b/libs/openengine/bullet/trace.h index 076baf56e..1bfe0c717 100644 --- a/libs/openengine/bullet/trace.h +++ b/libs/openengine/bullet/trace.h @@ -5,9 +5,8 @@ #include #include #include -#include #include - +#include "pmove.h" enum traceWorldType diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp index 41b7773ea..ba532b527 100644 --- a/libs/openengine/ogre/fader.cpp +++ b/libs/openengine/ogre/fader.cpp @@ -1,52 +1,50 @@ #include "fader.hpp" -#include -#include -#include #include #include #include #include +#include +#include -#define FADE_OVERLAY_NAME "FadeInOutOverlay" -#define FADE_OVERLAY_PANEL_NAME "FadeInOutOverlayPanel" -#define FADE_MATERIAL_NAME "FadeInOutMaterial" using namespace Ogre; using namespace OEngine::Render; -Fader::Fader() : - mMode(FadingMode_In), - mRemainingTime(0.f), - mTargetTime(0.f), - mTargetAlpha(0.f), - mCurrentAlpha(0.f), - mStartAlpha(0.f) +Fader::Fader(Ogre::SceneManager* sceneMgr) + : mSceneMgr(sceneMgr) + , mMode(FadingMode_In) + , mRemainingTime(0.f) + , mTargetTime(0.f) + , mTargetAlpha(0.f) + , mCurrentAlpha(0.f) + , mStartAlpha(0.f) { - // Create the fading material - MaterialPtr material = MaterialManager::getSingleton().create( FADE_MATERIAL_NAME, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); + MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); Pass* pass = material->getTechnique(0)->getPass(0); pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); mFadeTextureUnit = pass->createTextureUnitState(); mFadeTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(0.f, 0.f, 0.f)); // always black colour - // Create the overlay - OverlayManager& ovm = OverlayManager::getSingleton(); + mRectangle = new Ogre::Rectangle2D(true); + mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0); + mRectangle->setMaterial("FadeInOutMaterial"); + mRectangle->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY-1); + // Use infinite AAB to always stay visible + Ogre::AxisAlignedBox aabInf; + aabInf.setInfinite(); + mRectangle->setBoundingBox(aabInf); + // Attach background to the scene + Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + node->attachObject(mRectangle); + mRectangle->setVisible(false); + mRectangle->setVisibilityFlags (0x01); +} - mOverlay = ovm.create( FADE_OVERLAY_NAME ); - - OverlayContainer* overlay_panel; - overlay_panel = (OverlayContainer*)ovm.createOverlayElement("Panel", FADE_OVERLAY_PANEL_NAME); - - // position it over the whole screen - overlay_panel->_setPosition(0, 0); - overlay_panel->_setDimensions(1, 1); - - overlay_panel->setMaterialName( FADE_MATERIAL_NAME ); - overlay_panel->show(); - mOverlay->add2D(overlay_panel); - mOverlay->hide(); +Fader::~Fader() +{ + delete mRectangle; } void Fader::update(float dt) @@ -69,12 +67,12 @@ void Fader::update(float dt) mRemainingTime -= dt; } - if (mCurrentAlpha == 0.f) mOverlay->hide(); + if (mCurrentAlpha == 0.f) mRectangle->setVisible(false); } void Fader::applyAlpha() { - mOverlay->show(); + mRectangle->setVisible(true); mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, mCurrentAlpha); } diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp index efb12a5d2..bddf5dc91 100644 --- a/libs/openengine/ogre/fader.hpp +++ b/libs/openengine/ogre/fader.hpp @@ -4,52 +4,52 @@ /* A class that handles fading in the screen from black or fading it out to black. - To achieve this, it uses a full-screen Ogre::Overlay - - inspired by http://www.ogre3d.org/tikiwiki/FadeEffectOverlay (heavily adjusted) + To achieve this, it uses a full-screen Rectangle2d */ namespace Ogre { class TextureUnitState; - class Overlay; + class Rectangle2D; + class SceneManager; } namespace OEngine { namespace Render { - class Fader - { - public: - Fader(); - - void update(float dt); - - void fadeIn(const float time); - void fadeOut(const float time); - void fadeTo(const int percent, const float time); - - private: - enum FadingMode + class Fader { - FadingMode_In, - FadingMode_Out + public: + Fader(Ogre::SceneManager* sceneMgr); + ~Fader(); + + void update(float dt); + + void fadeIn(const float time); + void fadeOut(const float time); + void fadeTo(const int percent, const float time); + + private: + enum FadingMode + { + FadingMode_In, + FadingMode_Out + }; + + void applyAlpha(); + + Ogre::TextureUnitState* mFadeTextureUnit; + Ogre::Rectangle2D* mRectangle; + + FadingMode mMode; + + float mRemainingTime; + float mTargetTime; + float mTargetAlpha; + float mCurrentAlpha; + float mStartAlpha; + + Ogre::SceneManager* mSceneMgr; }; - - void applyAlpha(); - - Ogre::TextureUnitState* mFadeTextureUnit; - Ogre::Overlay* mOverlay; - - FadingMode mMode; - - float mRemainingTime; - float mTargetTime; - float mTargetAlpha; - float mCurrentAlpha; - float mStartAlpha; - - protected: - }; -}} + }} #endif diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 831b04930..87ebe1139 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -44,8 +44,10 @@ void OgreRenderer::cleanup() delete mFader; mFader = NULL; - OGRE_DELETE mRoot; + delete mRoot; mRoot = NULL; + + unloadPlugins(); } void OgreRenderer::start() @@ -78,7 +80,7 @@ void OgreRenderer::start() #endif } -bool OgreRenderer::loadPlugins() +void OgreRenderer::loadPlugins() { #ifdef ENABLE_PLUGIN_GL mGLPlugin = new Ogre::GLPlugin(); @@ -100,7 +102,30 @@ bool OgreRenderer::loadPlugins() mParticleFXPlugin = new Ogre::ParticleFXPlugin(); mRoot->installPlugin(mParticleFXPlugin); #endif - return true; +} + +void OgreRenderer::unloadPlugins() +{ + #ifdef ENABLE_PLUGIN_GL + delete mGLPlugin; + mGLPlugin = NULL; + #endif + #ifdef ENABLE_PLUGIN_Direct3D9 + delete mD3D9Plugin; + mD3D9Plugin = NULL; + #endif + #ifdef ENABLE_PLUGIN_CgProgramManager + delete mCgPlugin; + mCgPlugin = NULL; + #endif + #ifdef ENABLE_PLUGIN_OctreeSceneManager + delete mOctreePlugin; + mOctreePlugin = NULL; + #endif + #ifdef ENABLE_PLUGIN_ParticleFX + delete mParticleFXPlugin; + mParticleFXPlugin = NULL; + #endif } void OgreRenderer::update(float dt) @@ -120,6 +145,7 @@ float OgreRenderer::getFPS() void OgreRenderer::configure(const std::string &logPath, const std::string& renderSystem, + const std::string& rttMode, bool _logging) { // Set up logging first @@ -173,6 +199,9 @@ void OgreRenderer::configure(const std::string &logPath, if (rs == 0) throw std::runtime_error ("RenderSystem with name " + renderSystem + " not found, make sure the plugins are loaded"); mRoot->setRenderSystem(rs); + + if (rs->getName().find("OpenGL") != std::string::npos) + rs->setConfigOption ("RTT Preferred Mode", rttMode); } void OgreRenderer::createWindow(const std::string &title, const WindowSettings& settings) @@ -218,7 +247,7 @@ void OgreRenderer::createScene(const std::string& camName, float fov, float near // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio(Real(mView->getActualWidth()) / Real(mView->getActualHeight())); - mFader = new Fader(); + mFader = new Fader(mScene); } void OgreRenderer::adjustViewport() diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index 00e094b4d..a8788dfca 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -132,6 +132,7 @@ namespace OEngine void configure( const std::string &logPath, // Path to directory where to store log files const std::string &renderSystem, + const std::string &rttMode, bool _logging); // Enable or disable logging /// Create a window with the given title @@ -151,7 +152,9 @@ namespace OEngine /// Start the main rendering loop void start(); - bool loadPlugins() ; + void loadPlugins(); + + void unloadPlugins(); void update(float dt); diff --git a/libs/openengine/ogre/selectionbuffer.cpp b/libs/openengine/ogre/selectionbuffer.cpp index 3ecb99f3b..c6b43a45d 100644 --- a/libs/openengine/ogre/selectionbuffer.cpp +++ b/libs/openengine/ogre/selectionbuffer.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -73,7 +74,7 @@ namespace Render int id = Ogre::any_cast(subEntity->getParent ()->getUserObjectBindings().getUserAny()); bool found = false; Ogre::ColourValue colour; - for (std::map::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it) + for (std::map::iterator it = mColourMap.begin(); it != mColourMap.end(); ++it) { if (it->second == id) { diff --git a/readme.txt b/readme.txt index a254e2672..20aff18ae 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.17.0 +Version: 0.18.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -97,6 +97,39 @@ Allowed options: CHANGELOG +0.18.0 + +Bug #310: Button of the "preferences menu" are too small +Bug #361: Hand-to-hand skill is always 100 +Bug #365: NPC and creature animation is jerky; Characters float around when they are not supposed to +Bug #372: playSound3D uses original coordinates instead of current coordinates. +Bug #373: Static OGRE build faulty +Bug #375: Alt-tab toggle view +Bug #376: Screenshots are disable +Bug #378: Exception when drinking self-made potions +Bug #380: Cloth visibility problem +Bug #384: Weird character on doors tooltip. +Bug #398: Some objects do not collide in MW, but do so in OpenMW +Feature #22: Implement level-up +Feature #36: Hide Marker +Feature #88: Hotkey Window +Feature #91: Level-Up Dialogue +Feature #118: Keyboard and Mouse-Button bindings +Feature #119: Spell Buying Window +Feature #133: Handle resources across multiple data directories +Feature #134: Generate a suitable default-value for --data-local +Feature #292: Object Movement/Creation Script Instructions +Feature #340: AIPackage data structures +Feature #356: Ingredients use +Feature #358: Input system rewrite +Feature #370: Target handling in actions +Feature #379: Door markers on the local map +Feature #389: AI framework +Feature #395: Using keys to open doors / containers +Feature #396: Loading screens +Feature #397: Inventory avatar image and race selection head preview +Task #339: Move sounds into Action + 0.17.0 Bug #225: Valgrind reports about 40MB of leaked memory