diff --git a/CMakeLists.txt b/CMakeLists.txt index fcb5e9bbe..c11fda9f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ include (OpenMWMacros) # Version set (OPENMW_VERSION_MAJOR 0) -set (OPENMW_VERSION_MINOR 19) +set (OPENMW_VERSION_MINOR 20) set (OPENMW_VERSION_RELEASE 0) set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}") @@ -25,7 +25,8 @@ set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VE configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp") option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) -option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) +option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) +option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) # Apps and tools option(BUILD_ESMTOOL "build ESM inspector" ON) @@ -168,9 +169,9 @@ if (WIN32) set(PLATFORM_INCLUDE_DIR "platform") add_definitions(-DBOOST_ALL_NO_LIB) else (WIN32) -set(PLATFORM_INCLUDE_DIR "") -find_path (UUID_INCLUDE_DIR uuid/uuid.h) -include_directories(${UUID_INCLUDE_DIR}) + set(PLATFORM_INCLUDE_DIR "") + find_path (UUID_INCLUDE_DIR uuid/uuid.h) + include_directories(${UUID_INCLUDE_DIR}) endif (WIN32) if (MSVC10) set(PLATFORM_INCLUDE_DIR "") @@ -184,7 +185,7 @@ endif (APPLE) # Fix for not visible pthreads functions for linker with glibc 2.15 if (UNIX AND NOT APPLE) -find_package (Threads) + find_package (Threads) endif() # find boost without components so we can use Boost_VERSION @@ -197,6 +198,10 @@ if (Boost_VERSION LESS 104900) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} wave) endif() +IF(BOOST_STATIC) + set(Boost_USE_STATIC_LIBS ON) +endif() + find_package(OGRE REQUIRED) find_package(MyGUI REQUIRED) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) @@ -245,7 +250,7 @@ if (APPLE) else () set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG}) endif () - + #set(OGRE_PLUGIN_DIR "${OGRE_PLUGIN_DIR}/") configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 2da52311f..0563fdbbb 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -131,9 +131,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ->default_value(false), "enable console-only script functionality") ("script-run", bpo::value()->default_value(""), - "select a file that is executed in the console on startup\n\n" - "Note: The file contains a list of script lines, but not a complete scripts. " - "That means no begin/end and no variable declarations.") + "select a file containing a list of console commands that is executed on startup") ("new-game", bpo::value()->implicit_value(true) ->default_value(false), "activate char gen/new game mechanics") diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 31cef7f70..80316c0f5 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -110,14 +110,7 @@ namespace MWDialogue size_t pos = find_str_ci(text,*it,0); if(pos !=std::string::npos) { - if(pos==0) - { - mKnownTopics[*it] = true; - } - else if(text.substr(pos -1,1) == " ") - { - mKnownTopics[*it] = true; - } + mKnownTopics[*it] = true; } } updateTopics(); @@ -245,6 +238,44 @@ namespace MWDialogue } } + void DialogueManager::executeTopic (const std::string& topic) + { + Filter filter (mActor, mChoice, mTalkedTo); + + const MWWorld::Store &dialogues = + MWBase::Environment::get().getWorld()->getStore().get(); + + const ESM::Dialogue& dialogue = *dialogues.find (topic); + + if (const ESM::DialInfo *info = filter.search (dialogue)) + { + parseText (info->mResponse); + + MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); + + if (dialogue.mType==ESM::Dialogue::Persuasion) + { + std::string modifiedTopic = "s" + topic; + + modifiedTopic.erase (std::remove (modifiedTopic.begin(), modifiedTopic.end(), ' '), modifiedTopic.end()); + + const MWWorld::Store& gmsts = + MWBase::Environment::get().getWorld()->getStore().get(); + + win->addTitle (gmsts.find (modifiedTopic)->getString()); + } + else + win->addTitle (topic); + + win->addText (info->mResponse); + + executeScript (info->mResultScript); + + mLastTopic = topic; + mLastDialogue = *info; + } + } + void DialogueManager::updateTopics() { std::list keywordList; @@ -339,24 +370,7 @@ namespace MWDialogue ESM::Dialogue ndialogue = mDialogueMap[keyword]; if (mDialogueMap[keyword].mType == ESM::Dialogue::Topic) { - Filter filter (mActor, mChoice, mTalkedTo); - - if (const ESM::DialInfo *info = filter.search (mDialogueMap[keyword])) - { - std::string text = info->mResponse; - std::string script = info->mResultScript; - - parseText (text); - - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->addTitle (keyword); - win->addText (info->mResponse); - - executeScript (script); - - mLastTopic = keyword; - mLastDialogue = *info; - } + executeTopic (keyword); } } } @@ -452,30 +466,22 @@ namespace MWDialogue else if (curDisp + mTemporaryDispositionChange > 100) mTemporaryDispositionChange = 100 - curDisp; - // practice skill MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, success ? 0 : 1); - if (success) - MWWorld::Class::get(player).skillUsageSucceeded(player, ESM::Skill::Speechcraft, 0); - - // add status message to dialogue window std::string text; if (type == MWBase::MechanicsManager::PT_Admire) - text = "sAdmire"; + text = "Admire"; else if (type == MWBase::MechanicsManager::PT_Taunt) - text = "sTaunt"; + text = "Taunt"; else if (type == MWBase::MechanicsManager::PT_Intimidate) - text = "sIntimidate"; - else - text = "sBribe"; - - text += (success ? "Success" : "Fail"); - - MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->addTitle(MyGUI::LanguageManager::getInstance().replaceTags("#{"+text+"}")); + text = "Intimidate"; + else{ + text = "Bribe"; + } - /// \todo text from INFO record, how to get the ID? + executeTopic (text + (success ? " Success" : " Fail")); } int DialogueManager::getTemporaryDispositionChange() const diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 9e1971b0f..98b27f774 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -23,7 +23,7 @@ namespace MWDialogue MWScript::CompilerContext mCompilerContext; std::ostream mErrorStream; Compiler::StreamErrorHandler mErrorHandler; - + MWWorld::Ptr mActor; bool mTalkedTo; @@ -46,6 +46,8 @@ namespace MWDialogue void printError (const std::string& error); + void executeTopic (const std::string& topic); + public: DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose); diff --git a/apps/openmw/mwgui/alchemywindow.cpp b/apps/openmw/mwgui/alchemywindow.cpp index fc06e866c..db1a81c2c 100644 --- a/apps/openmw/mwgui/alchemywindow.cpp +++ b/apps/openmw/mwgui/alchemywindow.cpp @@ -63,7 +63,7 @@ namespace MWGui void AlchemyWindow::onCancelButtonClicked(MyGUI::Widget* _sender) { mAlchemy.clear(); - + mWindowManager.removeGuiMode(GM_Alchemy); mWindowManager.removeGuiMode(GM_Inventory); } @@ -119,7 +119,6 @@ namespace MWGui if (mIngredients[i]->isUserString("ToolTipType")) { MWWorld::Ptr ingred = *mIngredients[i]->getUserData(); - ingred.getRefData().setCount(ingred.getRefData().getCount()-1); if (ingred.getRefData().getCount() == 0) removeIngredient(mIngredients[i]); } diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index e4c9945b4..258e9174c 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -48,6 +48,11 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su return lower_string(str).find(lower_string(substr),pos); } +bool sortByLength (const std::string& left, const std::string& right) +{ + return left.size() > right.size(); +} + } @@ -287,7 +292,7 @@ void DialogueWindow::setKeywords(std::list keyWords) if (mServices & Service_Training) mTopicsList->addItem(gmst.find("sServiceTrainingTitle")->getString()); - if (anyService) + if (anyService || mPtr.getTypeName() == typeid(ESM::NPC).name()) mTopicsList->addSeparator(); for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); ++it) @@ -311,43 +316,52 @@ void addColorInString(std::string& str, const std::string& keyword,std::string c size_t pos = 0; while((pos = find_str_ci(str,keyword, pos)) != std::string::npos) { - if(pos==0) - { - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } - else + // do not add color if this portion of text is already colored. { - if(str.substr(pos -1,1) == " ") - { - str.insert(pos,color1); - pos += color1.length(); - pos += keyword.length(); - str.insert(pos,color2); - pos+= color2.length(); - } - else + MyGUI::TextIterator iterator (str); + MyGUI::UString colour; + while(iterator.moveNext()) { - pos += keyword.length(); + size_t iteratorPos = iterator.getPosition(); + iterator.getTagColour(colour); + if (iteratorPos == pos) + break; } + + if (colour == color1) + return; } + + str.insert(pos,color1); + pos += color1.length(); + pos += keyword.length(); + str.insert(pos,color2); + pos+= color2.length(); } } std::string DialogueWindow::parseText(std::string text) { bool separatorReached = false; // only parse topics that are below the separator (this prevents actions like "Barter" that are not topics from getting blue-colored) + + std::vector topics; + for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = mTopicsList->getItemNameAt(i); - if (separatorReached && keyWord != "") - addColorInString(text,keyWord,"#686EBA","#B29154"); - else + if (separatorReached) + topics.push_back(keyWord); + else if (keyWord == "") separatorReached = true; } + + // sort by length to make sure longer topics are replaced first + std::sort(topics.begin(), topics.end(), sortByLength); + + for(std::vector::const_iterator it = topics.begin(); it != topics.end(); ++it) + { + addColorInString(text,*it,"#686EBA","#B29154"); + } return text; } diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 8bcaa6ce0..d721e209a 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -226,9 +226,14 @@ namespace MWGui if (start == "splash") splash.push_back (*it); } - std::string randomSplash = splash[rand() % splash.size()]; + if (splash.size()) + { + std::string randomSplash = splash[rand() % splash.size()]; - Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); - mBackgroundImage->setImageTexture (randomSplash); + Ogre::TexturePtr tex = Ogre::TextureManager::getSingleton ().load (randomSplash, "General"); + mBackgroundImage->setImageTexture (randomSplash); + } + else + std::cerr << "No loading screens found!" << std::endl; } } diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 4b47bb025..70ceed857 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -252,11 +252,14 @@ void StatsWindow::onFrame () } setFactions(PCstats.getFactionRanks()); + setExpelled(PCstats.getExpelled ()); const std::string &signId = MWBase::Environment::get().getWorld()->getPlayer().getBirthSign(); setBirthSign(signId); + setReputation (PCstats.getReputation ()); + setBounty (PCstats.getBounty ()); if (mChanged) updateSkillArea(); @@ -271,6 +274,15 @@ void StatsWindow::setFactions (const FactionList& factions) } } +void StatsWindow::setExpelled (const std::set& expelled) +{ + if (mExpelled != expelled) + { + mExpelled = expelled; + mChanged = true; + } +} + void StatsWindow::setBirthSign (const std::string& signId) { if (signId != mBirthSignId) @@ -460,6 +472,10 @@ void StatsWindow::updateSkillArea() if (!mSkillWidgets.empty()) addSeparator(coord1, coord2); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + std::set& expelled = PCstats.getExpelled (); + addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); FactionList::const_iterator end = mFactions.end(); for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) @@ -471,36 +487,42 @@ void StatsWindow::updateSkillArea() std::string text; text += std::string("#DDC79E") + faction->mName; - text += std::string("\n#BF9959") + faction->mRanks[it->second]; - if (it->second < 9) + if (expelled.find(it->first) != expelled.end()) + text += "\n#{sExpelled}"; + else { - // player doesn't have max rank yet - text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; - - ESM::RankData rankData = faction->mData.mRankData[it->second+1]; - const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute1); - const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute2); - assert(attr1 && attr2); + text += std::string("\n#BF9959") + faction->mRanks[it->second]; - text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) - + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); - - text += "\n\n#DDC79E#{sFavoriteSkills}"; - text += "\n#BF9959"; - for (int i=0; i<6; ++i) + if (it->second < 9) { - text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; - if (i<5) - text += ", "; + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->mRanks[it->second+1]; + + ESM::RankData rankData = faction->mData.mRankData[it->second+1]; + const ESM::Attribute* attr1 = store.get().find(faction->mData.mAttribute1); + const ESM::Attribute* attr2 = store.get().find(faction->mData.mAttribute2); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->mName + "}: " + boost::lexical_cast(rankData.mAttribute1) + + ", #{" + attr2->mName + "}: " + boost::lexical_cast(rankData.mAttribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + text += "#{"+ESM::Skill::sSkillNameIds[faction->mData.mSkillID[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.mSkill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); + if (rankData.mSkill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); } - - text += "\n"; - - if (rankData.mSkill1 > 0) - text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.mSkill1); - if (rankData.mSkill2 > 0) - text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.mSkill2); } w->setUserString("ToolTipType", "Layout"); diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 5186b6328..6619680fa 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -38,8 +38,8 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); - void setReputation (int reputation) { this->mReputation = reputation; } - void setBounty (int bounty) { this->mBounty = bounty; } + void setReputation (int reputation) { if (reputation != mReputation) mChanged = true; this->mReputation = reputation; } + void setBounty (int bounty) { if (bounty != mBounty) mChanged = true; this->mBounty = bounty; } void updateSkillArea(); private: @@ -50,6 +50,7 @@ namespace MWGui MyGUI::Widget* addItem(const std::string& text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void setFactions (const FactionList& factions); + void setExpelled (const std::set& expelled); void setBirthSign (const std::string &signId); void onWindowResize(MyGUI::Window* window); @@ -71,6 +72,7 @@ namespace MWGui std::string mBirthSignId; int mReputation, mBounty; std::vector mSkillWidgets; //< Skills and other information + std::set mExpelled; bool mChanged; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 510bcb58f..97df211ac 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -31,6 +31,7 @@ ToolTips::ToolTips(MWBase::WindowManager* windowManager) : , mRemainingDelay(0.0) , mLastMouseX(0) , mLastMouseY(0) + , mHorizontalScrollIndex(0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -52,6 +53,7 @@ void ToolTips::setEnabled(bool enabled) void ToolTips::onFrame(float frameDuration) { + while (mDynamicToolTipBox->getChildCount()) { MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox->getChildAt(0)); @@ -103,7 +105,7 @@ void ToolTips::onFrame(float frameDuration) else { - const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); + const MyGUI::IntPoint& lastPressed = InputManager::getInstance().getLastPressedPosition(MyGUI::MouseButton::Left); if (mousePos == lastPressed) // mouseclick makes tooltip disappear return; @@ -114,11 +116,13 @@ void ToolTips::onFrame(float frameDuration) } else { + mHorizontalScrollIndex = 0; mRemainingDelay = mDelay; } mLastMouseX = mousePos.left; mLastMouseY = mousePos.top; + if (mRemainingDelay > 0) return; @@ -148,7 +152,8 @@ void ToolTips::onFrame(float frameDuration) { return; } - + + // special handling for markers on the local map: the tooltip should only be visible // if the marker is not hidden due to the fog of war. if (focus->getUserString ("IsMarker") == "true") @@ -354,7 +359,7 @@ void ToolTips::findImageExtension(std::string& image) } IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) -{ +{ mDynamicToolTipBox->setVisible(true); std::string caption = info.caption; @@ -388,6 +393,8 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) setCoord(0, 0, 300, 300); const IntPoint padding(8, 8); + + const int maximumWidth = 500; const int imageCaptionHPadding = (caption != "" ? 8 : 0); const int imageCaptionVPadding = (caption != "" ? 4 : 0); @@ -411,7 +418,7 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) IntSize textSize = textWidget->getTextSize(); captionSize += IntSize(imageSize, 0); // adjust for image - IntSize totalSize = IntSize( std::max(textSize.width, captionSize.width + ((image != "") ? imageCaptionHPadding : 0)), + IntSize totalSize = IntSize( std::min(std::max(textSize.width,captionSize.width + ((image != "") ? imageCaptionHPadding : 0)),maximumWidth), ((text != "") ? textSize.height + imageCaptionVPadding : 0) + captionHeight ); if (!info.effects.empty()) @@ -499,8 +506,24 @@ IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) (captionHeight-captionSize.height)/2, captionSize.width-imageSize, captionSize.height); + + //if its too long we do hscroll with the caption + if (captionSize.width > maximumWidth){ + mHorizontalScrollIndex = mHorizontalScrollIndex + 2; + if (mHorizontalScrollIndex > captionSize.width){ + mHorizontalScrollIndex = -totalSize.width; + } + int horizontal_scroll = mHorizontalScrollIndex; + if (horizontal_scroll < 40){ + horizontal_scroll = 40; + }else{ + horizontal_scroll = 80 - mHorizontalScrollIndex; + } + captionWidget->setPosition (IntPoint(horizontal_scroll, captionWidget->getPosition().top + padding.top)); + } else { + captionWidget->setPosition (captionWidget->getPosition() + padding); + } - captionWidget->setPosition (captionWidget->getPosition() + padding); textWidget->setPosition (textWidget->getPosition() + IntPoint(0, padding.top)); // only apply vertical padding, the horizontal works automatically due to Align::HCenter if (image != "") diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index 270df4ae2..4048d0d5a 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -90,6 +90,9 @@ namespace MWGui float mFocusToolTipX; float mFocusToolTipY; + + int mHorizontalScrollIndex; + float mDelay; float mRemainingDelay; // remaining time until tooltip will show diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index c6a21c461..a005c618f 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -211,7 +211,7 @@ namespace MWGui + MWBase::Environment::get().getDialogueManager()->getTemporaryDispositionChange()),100)); MWMechanics::NpcStats sellerSkill = MWWorld::Class::get(mPtr).getNpcStats(mPtr); - MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(mPtr).getCreatureStats(mPtr); + MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(mPtr).getCreatureStats(mPtr); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); MWMechanics::CreatureStats playerStats = MWWorld::Class::get(playerPtr).getCreatureStats(playerPtr); @@ -239,7 +239,10 @@ namespace MWGui MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterFailDisposition); return; } - } + + //skill use! + MWWorld::Class::get(playerPtr).skillUsageSucceeded(playerPtr, ESM::Skill::Mercantile, 0); + } int iBarterSuccessDisposition = gmst.find("iBarterSuccessDisposition")->getInt(); MWBase::Environment::get().getDialogueManager()->applyTemporaryDispositionChange(iBarterSuccessDisposition); diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 31b5cce35..4f2c98c08 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -204,6 +204,7 @@ namespace MWGui MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); mProgressBar.setVisible (false); mWindowManager.removeGuiMode (GM_Rest); + mWindowManager.removeGuiMode (GM_RestBed); mWaiting = false; MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index af30c9b04..6a1c3aa9b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -624,7 +624,9 @@ namespace MWInput void InputManager::toggleAutoMove() { if (mWindows.isGuiMode()) return; - mPlayer.setAutoMove (!mPlayer.getAutoMove()); + + if (mControlSwitch["playercontrols"]) + mPlayer.setAutoMove (!mPlayer.getAutoMove()); } void InputManager::toggleWalking() diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 989bdedd7..f53ccdce3 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -3,6 +3,8 @@ #include +#include + #include #include #include @@ -258,4 +260,18 @@ namespace MWMechanics return scaledDuration-usedUp; } + + bool ActiveSpells::isSpellActive(std::string id) const + { + boost::algorithm::to_lower(id); + for (TContainer::iterator iter = mSpells.begin(); iter != mSpells.end(); ++iter) + { + std::string left = iter->first; + boost::algorithm::to_lower(left); + + if (iter->first == id) + return true; + } + return false; + } } diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index e7a239854..6b832f4cd 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -58,6 +58,9 @@ namespace MWMechanics void removeSpell (const std::string& id); + bool isSpellActive (std::string id) const; + ///< case insensitive + const MagicEffects& getMagicEffects() const; TIterator begin() const; diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index c07c60209..8ab81bfdf 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -203,7 +203,7 @@ const ESM::Potion *MWMechanics::Alchemy::getRecord() const bool mismatch = false; - for (int i=0; i (iter->mEffects.mList.size()); ++iter) + for (int i=0; i (iter->mEffects.mList.size()); ++i) { const ESM::ENAMstruct& first = iter->mEffects.mList[i]; const ESM::ENAMstruct& second = mEffects[i]; diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 1b6e4b9f3..079f8520b 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -38,7 +38,7 @@ namespace MWMechanics creatureStats.getAttribute(5).setBase (player->mNpdt52.mEndurance); creatureStats.getAttribute(6).setBase (player->mNpdt52.mPersonality); creatureStats.getAttribute(7).setBase (player->mNpdt52.mLuck); - + const MWWorld::ESMStore &esmStore = MWBase::Environment::get().getWorld()->getStore(); @@ -46,7 +46,7 @@ namespace MWMechanics if (mRaceSelected) { const ESM::Race *race = - esmStore.get().find(player->mRace); + esmStore.get().find(player->mRace); bool male = (player->mFlags & ESM::NPC::Female) == 0; @@ -72,14 +72,14 @@ namespace MWMechanics for (int i=0; i<27; ++i) { int bonus = 0; - + for (int i2=0; i2<7; ++i2) if (race->mData.mBonus[i2].mSkill==i) { bonus = race->mData.mBonus[i2].mBonus; break; } - + npcStats.getSkill (i).setBase (5 + bonus); } @@ -270,7 +270,7 @@ namespace MWMechanics // basic player profile; should not change anymore after the creation phase is finished. MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); - + MWBase::World *world = MWBase::Environment::get().getWorld(); const ESM::NPC *player = world->getPlayer().getPlayer().get()->mBase; @@ -442,7 +442,7 @@ namespace MWMechanics if (playerStats.hasCommonDisease() || playerStats.hasBlightDisease()) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispDiseaseMod")->getFloat(); - if (playerNpcStats.getDrawState() == MWMechanics::DrawState_::DrawState_Weapon) + if (playerNpcStats.getDrawState() == MWMechanics::DrawState_Weapon) x += MWBase::Environment::get().getWorld()->getStore().get().find("fDispWeaponDrawn")->getFloat(); int effective_disposition = std::max(0,std::min(int(x),100));//, normally clamped to [0..100] when used @@ -455,7 +455,7 @@ namespace MWMechanics return basePrice; MWMechanics::NpcStats sellerSkill = MWWorld::Class::get(ptr).getNpcStats(ptr); - MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); + MWMechanics::CreatureStats sellerStats = MWWorld::Class::get(ptr).getCreatureStats(ptr); MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); MWMechanics::NpcStats playerSkill = MWWorld::Class::get(playerPtr).getNpcStats(playerPtr); @@ -471,13 +471,13 @@ namespace MWMechanics float d = std::min(sellerSkill.getSkill(ESM::Skill::Mercantile).getModified(), 100.f); float e = std::min(0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(), 10.f); float f = std::min(0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(), 10.f); - + float pcTerm = (clampedDisposition - 50 + a + b + c) * playerStats.getFatigueTerm(); float npcTerm = (d + e + f) * sellerStats.getFatigueTerm(); float buyTerm = 0.01 * (100 - 0.5 * (pcTerm - npcTerm)); float sellTerm = 0.01 * (50 - 0.5 * (npcTerm - pcTerm)); - float x; + float x; if(buying) x = buyTerm; else x = std::min(buyTerm, sellTerm); int offerPrice; diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 20a0360e7..26c4c8e9a 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -117,12 +117,15 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (usageType>=4) throw std::runtime_error ("skill usage type out of range"); - if (usageType>0) + if (usageType>=0) { skillFactor = skill->mData.mUseValue[usageType]; - if (skillFactor<=0) + if (skillFactor<0) throw std::runtime_error ("invalid skill gain factor"); + + if (skillFactor==0) + return 0; } const MWWorld::Store &gmst = @@ -217,7 +220,7 @@ void MWMechanics::NpcStats::increaseSkill(int skillIndex, const ESM::Class &clas std::stringstream message; message << boost::format(MWBase::Environment::get().getWindowManager ()->getGameSettingString ("sNotifyMessage39", "")) % std::string("#{" + ESM::Skill::sSkillNameIds[skillIndex] + "}") - % base; + % static_cast (base); MWBase::Environment::get().getWindowManager ()->messageBox(message.str(), std::vector()); if (mLevelProgress >= 10) @@ -350,4 +353,4 @@ void MWMechanics::NpcStats::setWerewolf (bool set) int MWMechanics::NpcStats::getWerewolfKills() const { return mWerewolfKills; -} \ No newline at end of file +} diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 14392fc49..a1a24b7ba 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -337,6 +337,8 @@ void RenderingManager::update (float duration, bool paused) mVideoPlayer->update (); + mRendering.update(duration); + if(paused) { Ogre::ControllerManager::getSingleton().setTimeFactor(0.f); @@ -355,8 +357,6 @@ void RenderingManager::update (float duration, bool paused) mSkyManager->setGlare(mOcclusionQuery->getSunVisibility()); - mRendering.update(duration); - MWWorld::RefData &data = MWBase::Environment::get() .getWorld() diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 787962ad1..aa1d2d030 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -114,71 +114,56 @@ namespace MWScript // discard additional arguments (reset), because we have no idea what they mean. for (unsigned int i=0; i - class OpSetHello : public Interpreter::Opcode0 + class OpGetAiSetting : public Interpreter::Opcode0 { + int mIndex; public: + OpGetAiSetting(int index) : mIndex(index) {} 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).setAiSetting (0, value); + runtime.push(MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (mIndex)); } }; - template - class OpSetFight : public Interpreter::Opcode0 + class OpModAiSetting : public Interpreter::Opcode0 { + int mIndex; public: + OpModAiSetting(int index) : mIndex(index) {} 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).setAiSetting (1, value); + MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (mIndex, + MWWorld::Class::get (ptr).getCreatureStats (ptr).getAiSetting (mIndex) + value); } }; - template - class OpSetFlee : public Interpreter::Opcode0 + class OpSetAiSetting : public Interpreter::Opcode0 { + int mIndex; public: + OpSetAiSetting(int index) : mIndex(index) {} 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).setAiSetting (2, value); - } - }; - - template - class OpSetAlarm : 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).setAiSetting (3, value); + MWWorld::Class::get (ptr).getCreatureStats (ptr).setAiSetting (mIndex, + value); } }; @@ -199,6 +184,22 @@ namespace MWScript const int opcodeSetFleeExplicit = 0x2000161; const int opcodeSetAlarm = 0x2000162; const int opcodeSetAlarmExplicit = 0x2000163; + const int opcodeModHello = 0x20001b7; + const int opcodeModHelloExplicit = 0x20001b8; + const int opcodeModFight = 0x20001b9; + const int opcodeModFightExplicit = 0x20001ba; + const int opcodeModFlee = 0x20001bb; + const int opcodeModFleeExplicit = 0x20001bc; + const int opcodeModAlarm = 0x20001bd; + const int opcodeModAlarmExplicit = 0x20001be; + const int opcodeGetHello = 0x20001bf; + const int opcodeGetHelloExplicit = 0x20001c0; + const int opcodeGetFight = 0x20001c1; + const int opcodeGetFightExplicit = 0x20001c2; + const int opcodeGetFlee = 0x20001c3; + const int opcodeGetFleeExplicit = 0x20001c4; + const int opcodeGetAlarm = 0x20001c5; + const int opcodeGetAlarmExplicit = 0x20001c6; void registerExtensions (Compiler::Extensions& extensions) { @@ -216,6 +217,14 @@ namespace MWScript extensions.registerInstruction ("setfight", "l", opcodeSetFight, opcodeSetFightExplicit); extensions.registerInstruction ("setflee", "l", opcodeSetFlee, opcodeSetFleeExplicit); extensions.registerInstruction ("setalarm", "l", opcodeSetAlarm, opcodeSetAlarmExplicit); + extensions.registerInstruction ("modhello", "l", opcodeModHello, opcodeModHelloExplicit); + extensions.registerInstruction ("modfight", "l", opcodeModFight, opcodeModFightExplicit); + extensions.registerInstruction ("modflee", "l", opcodeModFlee, opcodeModFleeExplicit); + extensions.registerInstruction ("modalarm", "l", opcodeModAlarm, opcodeModAlarmExplicit); + extensions.registerFunction ("gethello", 'l', "", opcodeGetHello, opcodeGetHelloExplicit); + extensions.registerFunction ("getfight", 'l', "", opcodeGetFight, opcodeGetFightExplicit); + extensions.registerFunction ("getflee", 'l', "", opcodeGetFlee, opcodeGetFleeExplicit); + extensions.registerFunction ("getalarm", 'l', "", opcodeGetAlarm, opcodeGetAlarmExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -229,14 +238,32 @@ namespace MWScript interpreter.installSegment5 (opcodeGetAiPackageDone, new OpGetAiPackageDone); interpreter.installSegment5 (opcodeGetAiPackageDoneExplicit, new OpGetAiPackageDone); - interpreter.installSegment5 (opcodeSetHello, new OpSetHello); - interpreter.installSegment5 (opcodeSetHelloExplicit, new OpSetHello); - interpreter.installSegment5 (opcodeSetFight, new OpSetFight); - interpreter.installSegment5 (opcodeSetFightExplicit, new OpSetFight); - interpreter.installSegment5 (opcodeSetFlee, new OpSetFlee); - interpreter.installSegment5 (opcodeSetFleeExplicit, new OpSetFlee); - interpreter.installSegment5 (opcodeSetAlarm, new OpSetAlarm); - interpreter.installSegment5 (opcodeSetAlarmExplicit, new OpSetAlarm); + interpreter.installSegment5 (opcodeSetHello, new OpSetAiSetting(0)); + interpreter.installSegment5 (opcodeSetHelloExplicit, new OpSetAiSetting(0)); + interpreter.installSegment5 (opcodeSetFight, new OpSetAiSetting(1)); + interpreter.installSegment5 (opcodeSetFightExplicit, new OpSetAiSetting(1)); + interpreter.installSegment5 (opcodeSetFlee, new OpSetAiSetting(2)); + interpreter.installSegment5 (opcodeSetFleeExplicit, new OpSetAiSetting(2)); + interpreter.installSegment5 (opcodeSetAlarm, new OpSetAiSetting(3)); + interpreter.installSegment5 (opcodeSetAlarmExplicit, new OpSetAiSetting(3)); + + interpreter.installSegment5 (opcodeModHello, new OpModAiSetting(0)); + interpreter.installSegment5 (opcodeModHelloExplicit, new OpModAiSetting(0)); + interpreter.installSegment5 (opcodeModFight, new OpModAiSetting(1)); + interpreter.installSegment5 (opcodeModFightExplicit, new OpModAiSetting(1)); + interpreter.installSegment5 (opcodeModFlee, new OpModAiSetting(2)); + interpreter.installSegment5 (opcodeModFleeExplicit, new OpModAiSetting(2)); + interpreter.installSegment5 (opcodeModAlarm, new OpModAiSetting(3)); + interpreter.installSegment5 (opcodeModAlarmExplicit, new OpModAiSetting(3)); + + interpreter.installSegment5 (opcodeGetHello, new OpGetAiSetting(0)); + interpreter.installSegment5 (opcodeGetHelloExplicit, new OpGetAiSetting(0)); + interpreter.installSegment5 (opcodeGetFight, new OpGetAiSetting(1)); + interpreter.installSegment5 (opcodeGetFightExplicit, new OpGetAiSetting(1)); + interpreter.installSegment5 (opcodeGetFlee, new OpGetAiSetting(2)); + interpreter.installSegment5 (opcodeGetFleeExplicit, new OpGetAiSetting(2)); + interpreter.installSegment5 (opcodeGetAlarm, new OpGetAiSetting(3)); + interpreter.installSegment5 (opcodeGetAlarmExplicit, new OpGetAiSetting(3)); } } } diff --git a/apps/openmw/mwscript/containerextensions.cpp b/apps/openmw/mwscript/containerextensions.cpp index 5e9746b2f..7f4913b8a 100644 --- a/apps/openmw/mwscript/containerextensions.cpp +++ b/apps/openmw/mwscript/containerextensions.cpp @@ -14,6 +14,8 @@ #include "../mwworld/manualref.hpp" #include "../mwworld/class.hpp" #include "../mwworld/containerstore.hpp" +#include "../mwworld/actionequip.hpp" +#include "../mwworld/inventorystore.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -128,12 +130,196 @@ namespace MWScript } }; + template + class OpEquip : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (toLower(it->getCellRef().mRefID) == toLower(item)) + break; + } + if (it == invStore.end()) + throw std::runtime_error("Item to equip not found"); + + MWWorld::ActionEquip action (*it); + action.execute(ptr); + } + }; + + template + class OpGetArmorType : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Integer location = runtime[0].mInteger; + runtime.pop(); + + int slot; + switch (location) + { + case 0: + slot = MWWorld::InventoryStore::Slot_Helmet; + break; + case 1: + slot = MWWorld::InventoryStore::Slot_Cuirass; + break; + case 2: + slot = MWWorld::InventoryStore::Slot_LeftPauldron; + break; + case 3: + slot = MWWorld::InventoryStore::Slot_RightPauldron; + break; + case 4: + slot = MWWorld::InventoryStore::Slot_Greaves; + break; + case 5: + slot = MWWorld::InventoryStore::Slot_Boots; + break; + case 6: + slot = MWWorld::InventoryStore::Slot_LeftGauntlet; + break; + case 7: + slot = MWWorld::InventoryStore::Slot_RightGauntlet; + break; + case 8: + slot = MWWorld::InventoryStore::Slot_CarriedLeft; // shield + break; + case 9: + slot = MWWorld::InventoryStore::Slot_LeftGauntlet; + break; + case 10: + slot = MWWorld::InventoryStore::Slot_RightGauntlet; + break; + default: + throw std::runtime_error ("armor index out of range"); + } + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + + MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); + if (it == invStore.end() || it->getTypeName () != typeid(ESM::Armor).name()) + { + runtime.push(-1); + return; + } + + int skill = MWWorld::Class::get(*it).getEquipmentSkill (*it) ; + if (skill == ESM::Skill::HeavyArmor) + runtime.push(2); + else if (skill == ESM::Skill::MediumArmor) + runtime.push(1); + else if (skill == ESM::Skill::LightArmor) + runtime.push(0); + else + runtime.push(-1); + } + }; + + template + class OpHasItemEquipped : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string item = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot (slot); + if (it != invStore.end() && toLower(it->getCellRef().mRefID) == toLower(item)) + { + runtime.push(1); + return; + } + } + runtime.push(0); + } + }; + + template + class OpHasSoulGem : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string creatureName = toLower (runtime.getStringLiteral (runtime[0].mInteger)); + runtime.pop(); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + for (MWWorld::ContainerStoreIterator it = invStore.begin(MWWorld::ContainerStore::Type_Miscellaneous); + it != invStore.end(); ++it) + { + + if (toLower(it->getCellRef().mSoul) == toLower(creatureName)) + { + runtime.push(1); + return; + } + } + runtime.push(0); + } + }; + + template + class OpGetWeaponType : public Interpreter::Opcode0 + { + public: + + virtual void execute(Interpreter::Runtime &runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(ptr).getInventoryStore (ptr); + MWWorld::ContainerStoreIterator it = invStore.getSlot (MWWorld::InventoryStore::Slot_CarriedRight); + if (it == invStore.end() || it->getTypeName () != typeid(ESM::Weapon).name()) + { + runtime.push(-1); + return; + } + + runtime.push(it->get()->mBase->mData.mType); + } + }; + const int opcodeAddItem = 0x2000076; const int opcodeAddItemExplicit = 0x2000077; const int opcodeGetItemCount = 0x2000078; const int opcodeGetItemCountExplicit = 0x2000079; const int opcodeRemoveItem = 0x200007a; const int opcodeRemoveItemExplicit = 0x200007b; + const int opcodeEquip = 0x20001b3; + const int opcodeEquipExplicit = 0x20001b4; + const int opcodeGetArmorType = 0x20001d1; + const int opcodeGetArmorTypeExplicit = 0x20001d2; + const int opcodeHasItemEquipped = 0x20001d5; + const int opcodeHasItemEquippedExplicit = 0x20001d6; + const int opcodeHasSoulGem = 0x20001de; + const int opcodeHasSoulGemExplicit = 0x20001df; + const int opcodeGetWeaponType = 0x20001e0; + const int opcodeGetWeaponTypeExplicit = 0x20001e1; void registerExtensions (Compiler::Extensions& extensions) { @@ -142,6 +328,11 @@ namespace MWScript opcodeGetItemCountExplicit); extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, opcodeRemoveItemExplicit); + extensions.registerInstruction ("equip", "c", opcodeEquip, opcodeEquipExplicit); + extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit); + extensions.registerFunction ("hasitemequipped", 'l', "c", opcodeHasItemEquipped, opcodeHasItemEquippedExplicit); + extensions.registerFunction ("hassoulgem", 'l', "c", opcodeHasSoulGem, opcodeHasSoulGemExplicit); + extensions.registerFunction ("getweapontype", 'l', "", opcodeGetWeaponType, opcodeGetWeaponTypeExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -152,6 +343,16 @@ namespace MWScript interpreter.installSegment5 (opcodeGetItemCountExplicit, new OpGetItemCount); interpreter.installSegment5 (opcodeRemoveItem, new OpRemoveItem); interpreter.installSegment5 (opcodeRemoveItemExplicit, new OpRemoveItem); + interpreter.installSegment5 (opcodeEquip, new OpEquip); + interpreter.installSegment5 (opcodeEquipExplicit, new OpEquip); + interpreter.installSegment5 (opcodeGetArmorType, new OpGetArmorType); + interpreter.installSegment5 (opcodeGetArmorTypeExplicit, new OpGetArmorType); + interpreter.installSegment5 (opcodeHasItemEquipped, new OpHasItemEquipped); + interpreter.installSegment5 (opcodeHasItemEquippedExplicit, new OpHasItemEquipped); + interpreter.installSegment5 (opcodeHasSoulGem, new OpHasSoulGem); + interpreter.installSegment5 (opcodeHasSoulGemExplicit, new OpHasSoulGem); + interpreter.installSegment5 (opcodeGetWeaponType, new OpGetWeaponType); + interpreter.installSegment5 (opcodeGetWeaponTypeExplicit, new OpGetWeaponType); } } } diff --git a/apps/openmw/mwscript/controlextensions.cpp b/apps/openmw/mwscript/controlextensions.cpp index 0096c69ab..8d65dfdd5 100644 --- a/apps/openmw/mwscript/controlextensions.cpp +++ b/apps/openmw/mwscript/controlextensions.cpp @@ -106,6 +106,58 @@ namespace MWScript } }; + template + class OpGetForceRun : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats (ptr); + + runtime.push (npcStats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceRun)); + } + }; + + template + class OpGetForceSneak : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWMechanics::NpcStats& npcStats = MWWorld::Class::get(ptr).getNpcStats (ptr); + + runtime.push (npcStats.getMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); + } + }; + + class OpGetPcRunning : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + runtime.push (MWWorld::Class::get(ptr).getStance (ptr, MWWorld::Class::Run)); + } + }; + + class OpGetPcSneaking : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + runtime.push (MWWorld::Class::get(ptr).getStance (ptr, MWWorld::Class::Sneak)); + } + }; + const int numberOfControls = 7; const int opcodeEnable = 0x200007e; @@ -120,6 +172,12 @@ namespace MWScript const int opcodeForceSneak = 0x200015a; const int opcodeForceSneakExplicit = 0x200015b; const int opcodeGetDisabled = 0x2000175; + const int opcodeGetPcRunning = 0x20001c9; + const int opcodeGetPcSneaking = 0x20001ca; + const int opcodeGetForceRun = 0x20001cb; + const int opcodeGetForceSneak = 0x20001cc; + const int opcodeGetForceRunExplicit = 0x20001cd; + const int opcodeGetForceSneakExplicit = 0x20001ce; const char *controls[numberOfControls] = { @@ -151,6 +209,10 @@ namespace MWScript opcodeClearForceSneakExplicit); extensions.registerInstruction ("forcesneak", "", opcodeForceSneak, opcodeForceSneakExplicit); + extensions.registerFunction ("getpcrunning", 'l', "", opcodeGetPcRunning); + extensions.registerFunction ("getpcsneaking", 'l', "", opcodeGetPcSneaking); + extensions.registerFunction ("getforcerun", 'l', "", opcodeGetForceRun, opcodeGetForceRunExplicit); + extensions.registerFunction ("getforcesneak", 'l', "", opcodeGetForceSneak, opcodeGetForceSneakExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -181,6 +243,12 @@ namespace MWScript new OpClearMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); interpreter.installSegment5 (opcodeForceSneakExplicit, new OpSetMovementFlag (MWMechanics::NpcStats::Flag_ForceSneak)); + interpreter.installSegment5 (opcodeGetPcRunning, new OpGetPcRunning); + interpreter.installSegment5 (opcodeGetPcSneaking, new OpGetPcSneaking); + interpreter.installSegment5 (opcodeGetForceRun, new OpGetForceRun); + interpreter.installSegment5 (opcodeGetForceRunExplicit, new OpGetForceRun); + interpreter.installSegment5 (opcodeGetForceSneak, new OpGetForceSneak); + interpreter.installSegment5 (opcodeGetForceSneakExplicit, new OpGetForceSneak); } } } diff --git a/apps/openmw/mwscript/dialogueextensions.cpp b/apps/openmw/mwscript/dialogueextensions.cpp index 21c21acf0..f63623275 100644 --- a/apps/openmw/mwscript/dialogueextensions.cpp +++ b/apps/openmw/mwscript/dialogueextensions.cpp @@ -11,6 +11,10 @@ #include "../mwbase/dialoguemanager.hpp" #include "../mwbase/journal.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwmechanics/npcstats.hpp" + #include "interpretercontext.hpp" #include "ref.hpp" @@ -126,6 +130,64 @@ namespace MWScript } }; + template + class OpModReputation : 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).getNpcStats (ptr).setReputation (MWWorld::Class::get(ptr).getNpcStats (ptr).getReputation () + value); + } + }; + + template + class OpSetReputation : 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).getNpcStats (ptr).setReputation (value); + } + }; + + template + class OpGetReputation : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (MWWorld::Class::get(ptr).getNpcStats (ptr).getReputation ()); + } + }; + + template + class OpSameFaction : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer(); + + runtime.push (MWWorld::Class::get(ptr).getNpcStats (ptr).isSameFaction (MWWorld::Class::get(player).getNpcStats (player))); + } + }; + const int opcodeJournal = 0x2000133; const int opcodeSetJournalIndex = 0x2000134; const int opcodeGetJournalIndex = 0x2000135; @@ -134,6 +196,14 @@ namespace MWScript const int opcodeForceGreeting = 0x200014f; const int opcodeForceGreetingExplicit = 0x2000150; const int opcodeGoodbye = 0x2000152; + const int opcodeSetReputation = 0x20001ad; + const int opcodeModReputation = 0x20001ae; + const int opcodeSetReputationExplicit = 0x20001af; + const int opcodeModReputationExplicit = 0x20001b0; + const int opcodeGetReputation = 0x20001b1; + const int opcodeGetReputationExplicit = 0x20001b2; + const int opcodeSameFaction = 0x20001b5; + const int opcodeSameFactionExplicit = 0x20001b6; void registerExtensions (Compiler::Extensions& extensions) { @@ -146,6 +216,14 @@ namespace MWScript extensions.registerInstruction("forcegreeting","",opcodeForceGreeting, opcodeForceGreetingExplicit); extensions.registerInstruction("goodbye", "", opcodeGoodbye); + extensions.registerInstruction("setreputation", "l", opcodeSetReputation, + opcodeSetReputationExplicit); + extensions.registerInstruction("modreputation", "l", opcodeModReputation, + opcodeModReputationExplicit); + extensions.registerFunction("getreputation", 'l', "", opcodeGetReputation, + opcodeGetReputationExplicit); + extensions.registerFunction("samefaction", 'l', "", opcodeSameFaction, + opcodeSameFactionExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -158,6 +236,14 @@ namespace MWScript interpreter.installSegment5 (opcodeForceGreeting, new OpForceGreeting); interpreter.installSegment5 (opcodeForceGreetingExplicit, new OpForceGreeting); interpreter.installSegment5 (opcodeGoodbye, new OpGoodbye); + interpreter.installSegment5 (opcodeGetReputation, new OpGetReputation); + interpreter.installSegment5 (opcodeSetReputation, new OpSetReputation); + interpreter.installSegment5 (opcodeModReputation, new OpModReputation); + interpreter.installSegment5 (opcodeSetReputationExplicit, new OpSetReputation); + interpreter.installSegment5 (opcodeModReputationExplicit, new OpModReputation); + interpreter.installSegment5 (opcodeGetReputationExplicit, new OpGetReputation); + interpreter.installSegment5 (opcodeSameFaction, new OpSameFaction); + interpreter.installSegment5 (opcodeSameFactionExplicit, new OpSameFaction); } } diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index fdc4f4974..67379b8c0 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -37,7 +37,13 @@ op 0x20014: SetPCFacRep op 0x20015: SetPCFacRep, explicit reference op 0x20016: ModPCFacRep op 0x20017: ModPCFacRep, explicit reference -op s 0x20018-0x3ffff unused +op 0x20018: PcExpelled +op 0x20019: PcExpelled, explicit +op 0x2001a: PcExpell +op 0x2001b: PcExpell, explicit +op 0x2001c: PcClearExpelled +op 0x2001d: PcClearExpelled, explicit +op s 0x2001e-0x3ffff unused Segment 4: (not implemented yet) @@ -222,5 +228,72 @@ op 0x20001a9: CommonDisease, explicit reference op 0x20001aa: BlightDisease op 0x20001ab: BlightDisease, explicit reference op 0x20001ac: ToggleCollisionBoxes -opcodes 0x20001ac-0x3ffffff unused +op 0x20001ad: SetReputation +op 0x20001ae: ModReputation +op 0x20001af: SetReputation, explicit +op 0x20001b0: ModReputation, explicit +op 0x20001b1: GetReputation +op 0x20001b2: GetReputation, explicit +op 0x20001b3: Equip +op 0x20001b4: Equip, explicit +op 0x20001b5: SameFaction +op 0x20001b6: SameFaction, explicit +op 0x20001b7: ModHello +op 0x20001b8: ModHello, explicit reference +op 0x20001b9: ModFight +op 0x20001ba: ModFight, explicit reference +op 0x20001bb: ModFlee +op 0x20001bc: ModFlee, explicit reference +op 0x20001bd: ModAlarm +op 0x20001be: ModAlarm, explicit reference +op 0x20001bf: GetHello +op 0x20001c0: GetHello, explicit reference +op 0x20001c1: GetFight +op 0x20001c2: GetFight, explicit reference +op 0x20001c3: GetFlee +op 0x20001c4: GetFlee, explicit reference +op 0x20001c5: GetAlarm +op 0x20001c6: GetAlarm, explicit reference +op 0x20001c7: GetLocked +op 0x20001c8: GetLocked, explicit reference +op 0x20001c9: GetPcRunning +op 0x20001ca: GetPcSneaking +op 0x20001cb: GetForceRun +op 0x20001cc: GetForceSneak +op 0x20001cd: GetForceRun, explicit +op 0x20001ce: GetForceSneak, explicit +op 0x20001cf: GetEffect +op 0x20001d0: GetEffect, explicit +op 0x20001d1: GetArmorType +op 0x20001d2: GetArmorType, explicit +op 0x20001d3: GetAttacked +op 0x20001d4: GetAttacked, explicit +op 0x20001d5: HasItemEquipped +op 0x20001d6: HasItemEquipped, explicit +op 0x20001d7: GetWeaponDrawn +op 0x20001d8: GetWeaponDrawn, explicit +op 0x20001d9: GetRace +op 0x20001da: GetRace, explicit +op 0x20001db: GetSpellEffects +op 0x20001dc: GetSpellEffects, explicit +op 0x20001dd: GetCurrentTime +op 0x20001de: HasSoulGem +op 0x20001df: HasSoulGem, explicit +op 0x20001e0: GetWeaponType +op 0x20001e1: GetWeaponType, explicit +op 0x20001e2: GetWerewolfKills +op 0x20001e3: ModScale +op 0x20001e4: ModScale, explicit +op 0x20001e5: SetDelete +op 0x20001e6: SetDelete, explicit +op 0x20001e7: GetSquareRoot +op 0x20001e8: RaiseRank +op 0x20001e9: RaiseRank, explicit +op 0x20001ea: LowerRank +op 0x20001eb: LowerRank, explicit +op 0x20001ec: PlayBink + +opcodes 0x20001ed-0x3ffffff unused + + diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index a775be13c..ef9976a0b 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -13,6 +13,10 @@ #include "../mwbase/windowmanager.hpp" #include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" + +#include "../mwmechanics/npcstats.hpp" +#include "../mwmechanics/creaturestats.hpp" #include "interpretercontext.hpp" #include "ref.hpp" @@ -285,6 +289,121 @@ namespace MWScript }; bool OpToggleVanityMode::sActivate = true; + template + class OpGetLocked : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push (ptr.getCellRef ().mLockLevel > 0); + } + }; + + template + class OpGetEffect : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + int key = runtime[0].mInteger; + runtime.pop(); + + runtime.push (MWWorld::Class::get(ptr).getCreatureStats (ptr).getMagicEffects ().get ( + MWMechanics::EffectKey(key)).mMagnitude > 0); + } + }; + + template + class OpGetAttacked : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push(MWWorld::Class::get(ptr).getCreatureStats (ptr).getAttacked ()); + } + }; + + template + class OpGetWeaponDrawn : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + runtime.push(MWWorld::Class::get(ptr).getNpcStats (ptr).getDrawState () == MWMechanics::DrawState_Weapon); + } + }; + + template + class OpGetSpellEffects : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + std::string id = runtime.getStringLiteral(runtime[0].mInteger); + runtime.pop(); + + runtime.push(MWWorld::Class::get(ptr).getCreatureStats(ptr).getActiveSpells().isSpellActive(id)); + } + }; + + class OpGetCurrentTime : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.push(MWBase::Environment::get().getWorld()->getTimeStamp().getHour()); + } + }; + + template + class OpSetDelete : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + int parameter = runtime[0].mInteger; + runtime.pop(); + + if (parameter == 1) + { + if (ptr.isInCell()) + MWBase::Environment::get().getWorld()->deleteObject (ptr); + else + ptr.getRefData().setCount(0); + } + } + }; + + class OpGetSquareRoot : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + float param = runtime[0].mFloat; + runtime.pop(); + + runtime.push(std::sqrt (param)); + } + }; + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -304,8 +423,22 @@ namespace MWScript const int opcodeToggleVanityMode = 0x2000174; const int opcodeGetPcSleep = 0x200019f; const int opcodeWakeUpPc = 0x20001a2; - - const int opcodePlayBink = 0x20001a3; + const int opcodeGetLocked = 0x20001c7; + const int opcodeGetLockedExplicit = 0x20001c8; + const int opcodeGetEffect = 0x20001cf; + const int opcodeGetEffectExplicit = 0x20001d0; + const int opcodeGetAttacked = 0x20001d3; + const int opcodeGetAttackedExplicit = 0x20001d4; + const int opcodeGetWeaponDrawn = 0x20001d7; + const int opcodeGetWeaponDrawnExplicit = 0x20001d8; + const int opcodeGetSpellEffects = 0x20001db; + const int opcodeGetSpellEffectsExplicit = 0x20001dc; + const int opcodeGetCurrentTime = 0x20001dd; + const int opcodeSetDelete = 0x20001e5; + const int opcodeSetDeleteExplicit = 0x20001e6; + const int opcodeGetSquareRoot = 0x20001e7; + + const int opcodePlayBink = 0x20001ec; void registerExtensions (Compiler::Extensions& extensions) { @@ -332,8 +465,15 @@ namespace MWScript extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); extensions.registerInstruction ("wakeuppc", "", opcodeWakeUpPc); - extensions.registerInstruction ("playbink", "S", opcodePlayBink); + extensions.registerFunction ("getlocked", 'l', "", opcodeGetLocked, opcodeGetLockedExplicit); + extensions.registerFunction ("geteffect", 'l', "l", opcodeGetEffect, opcodeGetEffectExplicit); + extensions.registerFunction ("getattacked", 'l', "", opcodeGetAttacked, opcodeGetAttackedExplicit); + extensions.registerFunction ("getweapondrawn", 'l', "", opcodeGetWeaponDrawn, opcodeGetWeaponDrawnExplicit); + extensions.registerFunction ("getspelleffects", 'l', "c", opcodeGetSpellEffects, opcodeGetSpellEffectsExplicit); + extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime); + extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit); + extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -357,8 +497,21 @@ namespace MWScript interpreter.installSegment5 (opcodeToggleVanityMode, new OpToggleVanityMode); interpreter.installSegment5 (opcodeGetPcSleep, new OpGetPcSleep); interpreter.installSegment5 (opcodeWakeUpPc, new OpWakeUpPc); - interpreter.installSegment5 (opcodePlayBink, new OpPlayBink); + interpreter.installSegment5 (opcodeGetLocked, new OpGetLocked); + interpreter.installSegment5 (opcodeGetLockedExplicit, new OpGetLocked); + interpreter.installSegment5 (opcodeGetEffect, new OpGetEffect); + interpreter.installSegment5 (opcodeGetEffectExplicit, new OpGetEffect); + interpreter.installSegment5 (opcodeGetAttacked, new OpGetAttacked); + interpreter.installSegment5 (opcodeGetAttackedExplicit, new OpGetAttacked); + interpreter.installSegment5 (opcodeGetWeaponDrawn, new OpGetWeaponDrawn); + interpreter.installSegment5 (opcodeGetWeaponDrawnExplicit, new OpGetWeaponDrawn); + interpreter.installSegment5 (opcodeGetSpellEffects, new OpGetSpellEffects); + interpreter.installSegment5 (opcodeGetSpellEffectsExplicit, new OpGetSpellEffects); + interpreter.installSegment5 (opcodeGetCurrentTime, new OpGetCurrentTime); + interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete); + interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete); + interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot); } } } diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index f6a31dd7f..c67782168 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -780,6 +780,210 @@ namespace MWScript } }; + template + class OpGetRace : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string race = runtime.getStringLiteral(runtime[0].mInteger); + boost::algorithm::to_lower(race); + runtime.pop(); + + std::string npcRace = ptr.get()->mBase->mRace; + boost::algorithm::to_lower(npcRace); + + runtime.push (npcRace == race); + } + }; + + class OpGetWerewolfKills : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld ()->getPlayer ().getPlayer (); + + runtime.push (MWWorld::Class::get(ptr).getNpcStats (ptr).getWerewolfKills ()); + } + }; + + template + class OpPcExpelled : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(arg0 >0 ) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + { + factionID = ""; + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + } + boost::algorithm::to_lower(factionID); + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(factionID!="") + { + std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); + if (expelled.find (factionID) != expelled.end()) + { + runtime.push(1); + } + else + { + runtime.push(0); + } + } + else + { + runtime.push(0); + } + } + }; + + template + class OpPcExpell : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(arg0 >0 ) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + { + factionID = ""; + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(factionID!="") + { + std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); + boost::algorithm::to_lower(factionID); + expelled.insert(factionID); + } + } + }; + + template + class OpPcClearExpelled : public Interpreter::Opcode1 + { + public: + + virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(arg0 >0 ) + { + factionID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + } + else + { + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + { + factionID = ""; + } + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + if(factionID!="") + { + std::set& expelled = MWWorld::Class::get(player).getNpcStats(player).getExpelled (); + boost::algorithm::to_lower(factionID); + expelled.erase (factionID); + } + } + }; + + template + class OpRaiseRank : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + return; + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + // no-op when executed on the player + if (ptr == player) + return; + + std::map& ranks = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks (); + ranks[factionID] = ranks[factionID]+1; + } + }; + + template + class OpLowerRank : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string factionID = ""; + if(MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().empty()) + return; + else + { + factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks().begin()->first; + } + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + // no-op when executed on the player + if (ptr == player) + return; + + std::map& ranks = MWWorld::Class::get(ptr).getNpcStats(ptr).getFactionRanks (); + ranks[factionID] = ranks[factionID]-1; + } + }; const int numberOfAttributes = 8; @@ -850,6 +1054,22 @@ namespace MWScript const int opcodeGetBlightDisease = 0x20001aa; const int opcodeGetBlightDiseaseExplicit = 0x20001ab; + const int opcodeGetRace = 0x20001d9; + const int opcodeGetRaceExplicit = 0x20001da; + + const int opcodeGetWerewolfKills = 0x20001e2; + + const int opcodePcExpelled = 0x20018; + const int opcodePcExpelledExplicit = 0x20019; + const int opcodePcExpell = 0x2001a; + const int opcodePcExpellExplicit = 0x2001b; + const int opcodePcClearExpelled = 0x2001c; + const int opcodePcClearExpelledExplicit = 0x2001d; + const int opcodeRaiseRank = 0x20001e8; + const int opcodeRaiseRankExplicit = 0x20001e9; + const int opcodeLowerRank = 0x20001ea; + const int opcodeLowerRankExplicit = 0x20001eb; + void registerExtensions (Compiler::Extensions& extensions) { static const char *attributes[numberOfAttributes] = @@ -870,7 +1090,7 @@ namespace MWScript "alteration", "illusion", "conjuration", "mysticism", "restoration", "alchemy", "unarmored", "security", "sneak", "acrobatics", "lightarmor", "shortblade", "marksman", - "merchantile", "speechcraft", "handtohand" + "mercantile", "speechcraft", "handtohand" }; std::string get ("get"); @@ -950,6 +1170,15 @@ namespace MWScript opcodeGetCommonDiseaseExplicit); extensions.registerFunction ("getblightdisease", 'l', "", opcodeGetBlightDisease, opcodeGetBlightDiseaseExplicit); + + extensions.registerFunction ("getrace", 'l', "c", opcodeGetRace, + opcodeGetRaceExplicit); + extensions.registerFunction ("getwerewolfkills", 'f', "", opcodeGetWerewolfKills); + extensions.registerFunction ("pcexpelled", 'l', "/S", opcodePcExpelled, opcodePcExpelledExplicit); + extensions.registerInstruction ("pcexpell", "/S", opcodePcExpell, opcodePcExpellExplicit); + extensions.registerInstruction ("pcclearexpelled", "/S", opcodePcClearExpelled, opcodePcClearExpelledExplicit); + extensions.registerInstruction ("raiserank", "", opcodeRaiseRank, opcodeRaiseRankExplicit); + extensions.registerInstruction ("lowerrank", "", opcodeLowerRank, opcodeLowerRankExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -1045,6 +1274,21 @@ namespace MWScript interpreter.installSegment5 (opcodeGetCommonDiseaseExplicit, new OpGetCommonDisease); interpreter.installSegment5 (opcodeGetBlightDisease, new OpGetBlightDisease); interpreter.installSegment5 (opcodeGetBlightDiseaseExplicit, new OpGetBlightDisease); + + interpreter.installSegment5 (opcodeGetRace, new OpGetRace); + interpreter.installSegment5 (opcodeGetRaceExplicit, new OpGetRace); + interpreter.installSegment5 (opcodeGetWerewolfKills, new OpGetWerewolfKills); + + interpreter.installSegment3 (opcodePcExpelled, new OpPcExpelled); + interpreter.installSegment3 (opcodePcExpelledExplicit, new OpPcExpelled); + interpreter.installSegment3 (opcodePcExpell, new OpPcExpell); + interpreter.installSegment3 (opcodePcExpellExplicit, new OpPcExpell); + interpreter.installSegment3 (opcodePcClearExpelled, new OpPcClearExpelled); + interpreter.installSegment3 (opcodePcClearExpelledExplicit, new OpPcClearExpelled); + interpreter.installSegment5 (opcodeRaiseRank, new OpRaiseRank); + interpreter.installSegment5 (opcodeRaiseRankExplicit, new OpRaiseRank); + interpreter.installSegment5 (opcodeLowerRank, new OpLowerRank); + interpreter.installSegment5 (opcodeLowerRankExplicit, new OpLowerRank); } } } diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index a64651a97..2dd8f3e16 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -53,6 +53,23 @@ namespace MWScript } }; + template + class OpModScale : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float scale = runtime[0].mFloat; + runtime.pop(); + + // add the parameter to the object's scale. + MWBase::Environment::get().getWorld()->scaleObject(ptr,ptr.getCellRef().mScale + scale); + } + }; + template class OpSetAngle : public Interpreter::Opcode0 { @@ -532,6 +549,8 @@ namespace MWScript const int opcodePlaceAtPc = 0x200019c; const int opcodePlaceAtMe = 0x200019d; const int opcodePlaceAtMeExplicit = 0x200019e; + const int opcodeModScale = 0x20001e3; + const int opcodeModScaleExplicit = 0x20001e4; void registerExtensions (Compiler::Extensions& extensions) { @@ -548,6 +567,7 @@ namespace MWScript extensions.registerInstruction("placeitem","cffff",opcodePlaceItem); extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); + extensions.registerInstruction("modscale","f",opcodeModScale,opcodeModScaleExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -574,7 +594,9 @@ namespace MWScript interpreter.installSegment5(opcodePlaceItem,new OpPlaceItem); interpreter.installSegment5(opcodePlaceAtPc,new OpPlaceAtPc); interpreter.installSegment5(opcodePlaceAtMe,new OpPlaceAtMe); - interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); + interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); + interpreter.installSegment5(opcodeModScale,new OpModScale); + interpreter.installSegment5(opcodeModScaleExplicit,new OpModScale); } } } diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp index a2cccfd13..5f61ab8f0 100644 --- a/apps/openmw/mwsound/ffmpeg_decoder.cpp +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -313,7 +313,12 @@ void FFmpeg_Decoder::close() mStreams.erase(mStreams.begin()); } if(mFormatCtx) + { + AVIOContext* context = mFormatCtx->pb; + av_free(context); + mFormatCtx->pb = NULL; av_close_input_file(mFormatCtx); + } mFormatCtx = NULL; mDataStream.setNull(); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index fd93f39f1..046de8c63 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -287,6 +287,16 @@ namespace MWWorld public: typedef SharedIterator iterator; + virtual ~Store() + { + for (std::vector::const_iterator it = + mStatic.begin(); it != mStatic.end(); ++it) + { + delete *it; + } + + } + int getSize() const { return mStatic.size(); } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 0f9dd83d3..2257b8a07 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -193,7 +193,7 @@ namespace MWWorld mRendering->attachCameraTo(mPlayer->getPlayer()); mPhysics->addActor(mPlayer->getPlayer()); - + // global variables mGlobalVariables = new Globals (mStore); @@ -203,6 +203,8 @@ namespace MWWorld mGlobalVariables->setInt ("chargenstate", 1); } + mGlobalVariables->setInt ("pcrace", 3); + mWorldScene = new Scene(*mRendering, mPhysics); setFallbackValues(fallbackMap); @@ -660,7 +662,7 @@ namespace MWWorld { MWWorld::Class::get(ptr).adjustScale(ptr,scale); ptr.getCellRef().mScale = scale; - + if(ptr.getRefData().getBaseNode() == 0) return; mRendering->scaleObject(ptr, Vector3(scale,scale,scale)); @@ -673,7 +675,7 @@ namespace MWWorld rot.x = Ogre::Degree(x).valueRadians(); rot.y = Ogre::Degree(y).valueRadians(); rot.z = Ogre::Degree(z).valueRadians(); - + float *objRot = ptr.getRefData().getPosition().rot; if(ptr.getRefData().getBaseNode() == 0 || !mRendering->rotateObject(ptr, rot, adjust)) { @@ -781,7 +783,7 @@ namespace MWWorld const ESM::Potion *World::createRecord (const ESM::Potion& record) { - return mStore.insert(record); + return mStore.insert(record); } const ESM::Class *World::createRecord (const ESM::Class& record) @@ -802,7 +804,23 @@ namespace MWWorld const ESM::NPC *World::createRecord(const ESM::NPC &record) { bool update = false; - if (StringUtils::ciEqual(record.mId, "player")) { + + if (StringUtils::ciEqual(record.mId, "player")) + { + static const char *sRaces[] = + { + "Argonian", "Breton", "Dark Elf", "High Elf", "Imperial", "Khajiit", "Nord", "Orc", "Redguard", + "Woodelf", 0 + }; + + int i=0; + + for (; sRaces[i]; ++i) + if (StringUtils::ciEqual (sRaces[i], record.mRace)) + break; + + mGlobalVariables->setInt ("pcrace", sRaces[i] ? i+1 : 0); + const ESM::NPC *player = mPlayer->getPlayer().get()->mBase; @@ -834,7 +852,7 @@ namespace MWWorld /// \todo split this function up into subfunctions mWorldScene->update (duration, paused); - + float pitch, yaw; Ogre::Vector3 eyepos; mRendering->getPlayerData(eyepos, pitch, yaw); diff --git a/files/materials/core.h b/files/materials/core.h index e9577bbf3..1c9ea1d1d 100644 --- a/files/materials/core.h +++ b/files/materials/core.h @@ -1,5 +1,6 @@ -#define gammaCorrectRead(v) pow(v, float3(gammaCorrection,gammaCorrection,gammaCorrection)) -#define gammaCorrectOutput(v) pow(v, float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) +#define gammaCorrectRead(v) pow(max(v, 0.00001f), float3(gammaCorrection,gammaCorrection,gammaCorrection)) +#define gammaCorrectOutput(v) pow(max(v, 0.00001f), float3(1.f/gammaCorrection,1.f/gammaCorrection,1.f/gammaCorrection)) + #if SH_HLSL == 1 || SH_CG == 1 diff --git a/readme.txt b/readme.txt index 9a9010994..21ae85530 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.19.0 +Version: 0.20.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org @@ -69,12 +69,9 @@ Allowed options: --script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scri pts) at startup --script-console [=arg(=1)] (=0) enable console-only script functionality - --script-run arg select a file that is executed in the consol - e on startup + --script-run arg select a file containing a list of console + commands that is executed on startup - Note: The file contains a list of script - lines, but not a complete scripts. That mean - s no begin/end and no variable declarations. --new-game [=arg(=1)] (=0) activate char gen/new game mechanics --fs-strict [=arg(=1)] (=0) strict file system handling (no case folding ) @@ -97,6 +94,36 @@ Allowed options: CHANGELOG +0.20.0 + +Bug #366: Changing the player's race during character creation does not change the look of the player character +Bug #430: Teleporting and using loading doors linking within the same cell reloads the cell +Bug #437: Stop animations when paused +Bug #438: Time displays as "0 a.m." when it should be "12 a.m." +Bug #439: Text in "name" field of potion/spell creation window is persistent +Bug #440: Starting date at a new game is off by one day +Bug #442: Console window doesn't close properly sometimes +Bug #448: Do not break container window formatting when item names are very long +Bug #458: Topics sometimes not automatically added to known topic list +Bug #476: Auto-Moving allows player movement after using DisablePlayerControls +Bug #478: After sleeping in a bed the rest dialogue window opens automtically again +Bug #492: On creating potions the ingredients are removed twice +Feature #63: Mercantile skill +Feature #82: Persuasion Dialogue +Feature #219: Missing dialogue filters/functions +Feature #369: Add a FailedAction +Feature #377: Select head/hair on character creation +Feature #391: Dummy AI package classes +Feature #435: Global Map, 2nd Layer +Feature #450: Persuasion +Feature #457: Add more script instructions +Feature #474: update the global variable pcrace when the player's race is changed +Task #158: Move dynamically generated classes from Player class to World Class +Task #159: ESMStore rework and cleanup +Task #163: More Component Namespace Cleanup +Task #402: Move player data from MWWorld::Player to the player's NPC record +Task #446: Fix no namespace in BulletShapeLoader + 0.19.0 Bug #374: Character shakes in 3rd person mode near the origin