diff --git a/CMakeLists.txt b/CMakeLists.txt index 2f5e21c61..f83453cbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -102,7 +102,6 @@ set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(OENGINE_OGRE ${LIBDIR}/openengine/ogre/renderer.cpp - ${LIBDIR}/openengine/ogre/fader.cpp ${LIBDIR}/openengine/ogre/lights.cpp ${LIBDIR}/openengine/ogre/selectionbuffer.cpp ${LIBDIR}/openengine/ogre/imagerotate.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index d8966bdcf..14bf0ba17 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -33,7 +33,7 @@ add_openmw_dir (mwgui merchantrepair repair soulgemdialog companionwindow bookpage journalviewmodel journalbooks keywordsearch itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel fontloader controllers savegamedialog - recharge mode videowidget backgroundimage itemwidget + recharge mode videowidget backgroundimage itemwidget screenfader ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index f718972b9..532c1c3fa 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -128,6 +128,7 @@ namespace MWBase OffenseType type, int arg=0) = 0; virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0) = 0; + virtual void actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker) = 0; /// Utility to check if taking this item is illegal and calling commitCrime if so virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count) = 0; /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 8b407c9ba..f1c69e622 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -331,6 +331,15 @@ namespace MWBase virtual void removeCurrentModal(MWGui::WindowModal* input) = 0; virtual void pinWindow (MWGui::GuiWindow window) = 0; + + /// Fade the screen in, over \a time seconds + virtual void fadeScreenIn(const float time) = 0; + /// Fade the screen out to black, over \a time seconds + virtual void fadeScreenOut(const float time) = 0; + /// Fade the screen to a specified percentage of black, over \a time seconds + virtual void fadeScreenTo(const int percent, const float time) = 0; + /// Darken the screen by \a factor (1.0 = no darkening). Works independently from screen fading. + virtual void setScreenFactor (float factor) = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 62da2682d..a3a127d63 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -17,11 +17,6 @@ namespace Ogre namespace OEngine { - namespace Render - { - class Fader; - } - namespace Physic { class PhysicEngine; @@ -113,9 +108,6 @@ namespace MWBase virtual void readRecord (ESM::ESMReader& reader, int32_t type, const std::map& contentFileMap) = 0; - virtual OEngine::Render::Fader* getFader() = 0; - ///< \todo remove this function. Rendering details should not be exposed. - virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; @@ -271,8 +263,9 @@ namespace MWBase /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance) = 0; - virtual void adjustPosition (const MWWorld::Ptr& ptr) = 0; + virtual void adjustPosition (const MWWorld::Ptr& ptr, bool force) = 0; ///< Adjust position after load to be on ground. Must be called after model load. + /// @param force do this even if the ptr is flying virtual void fixPosition (const MWWorld::Ptr& actor) = 0; ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index b3fc5890b..f842528d3 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -157,15 +157,19 @@ namespace MWClass float iWeight = gmst.find (typeGmst)->getInt(); - if (iWeight * gmst.find ("fLightMaxMod")->getFloat()>= - ref->mBase->mData.mWeight) + float epsilon = 5e-4; + + if (ref->mBase->mData.mWeight == 0) + return ESM::Skill::Unarmored; + + if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fLightMaxMod")->getFloat() + epsilon) return ESM::Skill::LightArmor; - if (iWeight * gmst.find ("fMedMaxMod")->getFloat()>= - ref->mBase->mData.mWeight) + if (ref->mBase->mData.mWeight <= iWeight * gmst.find ("fMedMaxMod")->getFloat() + epsilon) return ESM::Skill::MediumArmor; - return ESM::Skill::HeavyArmor; + else + return ESM::Skill::HeavyArmor; } int Armor::getValue (const MWWorld::Ptr& ptr) const diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c175ce3eb..b6cb0e62d 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -148,9 +148,9 @@ namespace MWClass return ref->mBase->mId; } - void Creature::adjustPosition(const MWWorld::Ptr& ptr) const + void Creature::adjustPosition(const MWWorld::Ptr& ptr, bool force) const { - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } void Creature::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -255,23 +255,7 @@ namespace MWClass if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) { victim.getClass().onHit(victim, 0.0f, false, MWWorld::Ptr(), ptr, false); - - // Weapon health is reduced by 1 even if the attack misses - const bool weaphashealth = !weapon.isEmpty() && weapon.getClass().hasItemHealth(weapon); - if(weaphashealth) - { - int weaphealth = weapon.getClass().getItemHealth(weapon); - - if (!MWBase::Environment::get().getWorld()->getGodModeState()) - { - weaphealth -= std::min(1, weaphealth); - weapon.getCellRef().setCharge(weaphealth); - } - - // Weapon broken? unequip it - if (weapon.getCellRef().getCharge() == 0) - weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr); - } + MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); return; } @@ -298,7 +282,6 @@ namespace MWClass if (!weapon.isEmpty()) { - const bool weaphashealth = weapon.getClass().hasItemHealth(weapon); const unsigned char *attack = NULL; if(type == ESM::Weapon::AT_Chop) attack = weapon.get()->mBase->mData.mChop; @@ -309,26 +292,10 @@ namespace MWClass if(attack) { damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); - damage *= 0.5f + (stats.getAttribute(ESM::Attribute::Luck).getModified() / 100.0f); - if(weaphashealth) - { - int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); - int weaphealth = weapon.getClass().getItemHealth(weapon); - damage *= float(weaphealth) / weapmaxhealth; - - if (!MWBase::Environment::get().getWorld()->getGodModeState()) - { - // Reduce weapon charge by at least one, but cap at 0 - weaphealth -= std::min(std::max(1, - (int)(damage * gmst.find("fWeaponDamageMult")->getFloat())), weaphealth); - - weapon.getCellRef().setCharge(weaphealth); - } - - // Weapon broken? unequip it - if (weapon.getCellRef().getCharge() == 0) - weapon = *getInventoryStore(ptr).unequipItem(weapon, ptr); - } + damage *= gmst.find("fDamageStrengthBase")->getFloat() + + (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.find("fDamageStrengthMult")->getFloat() * 0.1); + MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); } // Apply "On hit" enchanted weapons @@ -366,16 +333,11 @@ namespace MWClass getCreatureStats(ptr).setAttacked(true); // Self defense - if ( ((!attacker.isEmpty() && attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr)) - || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) - && (canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures + if ((canWalk(ptr) || canFly(ptr) || canSwim(ptr)) // No retaliation for totally static creatures // (they have no movement or attacks anyway) - ) + && !attacker.isEmpty()) { - // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. - // Note: accidental or collateral damage attacks are ignored. - MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); + MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); } if(!successful) diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 6920a4b1d..1820d4ea4 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -49,7 +49,9 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; + ///< Adjust position to stand on ground. Must be called post model load + /// @param force do this even if the ptr is flying virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index d087febd0..a4a36602d 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -403,9 +403,9 @@ namespace MWClass return ref->mBase->mId; } - void Npc::adjustPosition(const MWWorld::Ptr& ptr) const + void Npc::adjustPosition(const MWWorld::Ptr& ptr, bool force) const { - MWBase::Environment::get().getWorld()->adjustPosition(ptr); + MWBase::Environment::get().getWorld()->adjustPosition(ptr, force); } void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const @@ -529,24 +529,7 @@ namespace MWClass if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f) { othercls.onHit(victim, 0.0f, false, weapon, ptr, false); - - // Weapon health is reduced by 1 even if the attack misses - const bool weaphashealth = !weapon.isEmpty() && weapon.getClass().hasItemHealth(weapon); - if(weaphashealth) - { - int weaphealth = weapon.getClass().getItemHealth(weapon); - - if (!MWBase::Environment::get().getWorld()->getGodModeState()) - { - weaphealth -= std::min(1, weaphealth); - weapon.getCellRef().setCharge(weaphealth); - } - - // Weapon broken? unequip it - if (weaphealth == 0) - weapon = *inv.unequipItem(weapon, ptr); - } - + MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr); return; } @@ -555,7 +538,6 @@ namespace MWClass MWMechanics::NpcStats &stats = getNpcStats(ptr); if(!weapon.isEmpty()) { - const bool weaphashealth = weapon.getClass().hasItemHealth(weapon); const unsigned char *attack = NULL; if(type == ESM::Weapon::AT_Chop) attack = weapon.get()->mBase->mData.mChop; @@ -568,27 +550,9 @@ namespace MWClass damage = attack[0] + ((attack[1]-attack[0])*stats.getAttackStrength()); damage *= gmst.fDamageStrengthBase->getFloat() + (stats.getAttribute(ESM::Attribute::Strength).getModified() * gmst.fDamageStrengthMult->getFloat() * 0.1); - if(weaphashealth) - { - int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); - int weaphealth = weapon.getClass().getItemHealth(weapon); - - damage *= float(weaphealth) / weapmaxhealth; - - if (!MWBase::Environment::get().getWorld()->getGodModeState()) - { - // Reduce weapon charge by at least one, but cap at 0 - weaphealth -= std::min(std::max(1, - (int)(damage * store.find("fWeaponDamageMult")->getFloat())), weaphealth); - - weapon.getCellRef().setCharge(weaphealth); - } - - // Weapon broken? unequip it - if (weaphealth == 0) - weapon = *inv.unequipItem(weapon, ptr); - } } + MWMechanics::adjustWeaponDamage(damage, weapon); + MWMechanics::reduceWeaponCondition(damage, true, weapon, ptr); healthdmg = true; } else @@ -675,26 +639,13 @@ namespace MWClass // NOTE: 'object' and/or 'attacker' may be empty. - if (ptr != MWBase::Environment::get().getWorld()->getPlayerPtr()) - { - // Attacking peaceful NPCs is a crime - if (!attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) - && !MWBase::Environment::get().getMechanicsManager()->isAggressive(ptr, attacker)) - MWBase::Environment::get().getMechanicsManager()->commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); - - if (!attacker.isEmpty() && attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) - && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) - { - // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. - // Note: accidental or collateral damage attacks are ignored. - MWBase::Environment::get().getMechanicsManager()->startCombat(ptr, attacker); - } - } - bool wasDead = getCreatureStats(ptr).isDead(); getCreatureStats(ptr).setAttacked(true); + if (!attacker.isEmpty()) + MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); + if(!successful) { // TODO: Handle HitAttemptOnMe script function diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index b0ca0a658..71e34e498 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -55,7 +55,9 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics) const; - virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; + ///< Adjust position to stand on ground. Must be called post model load + /// @param force do this even if the ptr is flying virtual std::string getName (const MWWorld::Ptr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index f0212031e..0bdabb222 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -28,6 +28,16 @@ namespace MWGui { + DragAndDrop::DragAndDrop() + : mDraggedWidget(NULL) + , mDraggedCount(0) + , mSourceModel(NULL) + , mSourceView(NULL) + , mSourceSortModel(NULL) + , mIsOnDragAndDrop(NULL) + { + } + void DragAndDrop::startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count) { mItem = sourceModel->getItem(index); @@ -36,7 +46,6 @@ namespace MWGui mSourceView = sourceView; mSourceSortModel = sortModel; mIsOnDragAndDrop = true; - mDragAndDropWidget->setVisible(true); // If picking up an item that isn't from the player's inventory, the item gets added to player inventory backend // immediately, even though it's still floating beneath the mouse cursor. A bit counterintuitive, @@ -73,8 +82,13 @@ namespace MWGui mSourceSortModel->addDragItem(mItem.mBase, count); } - ItemWidget* baseWidget = mDragAndDropWidget->createWidget - ("MW_ItemIcon", MyGUI::IntCoord(0, 0, 42, 42), MyGUI::Align::Default); + ItemWidget* baseWidget = MyGUI::Gui::getInstance().createWidget("MW_ItemIcon", 0, 0, 42, 42, MyGUI::Align::Default, "DragAndDrop"); + + Controllers::ControllerFollowMouse* controller = + MyGUI::ControllerManager::getInstance().createItem(Controllers::ControllerFollowMouse::getClassTypeName()) + ->castType(); + MyGUI::ControllerManager::getInstance().addItem(baseWidget, controller); + mDraggedWidget = baseWidget; baseWidget->setItem(mItem.mBase); baseWidget->setNeedMouseFocus(false); @@ -99,8 +113,6 @@ namespace MWGui std::string sound = mItem.mBase.getClass().getDownSoundId(mItem.mBase); MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); - mDragAndDropWidget->setVisible(false); - // If item is dropped where it was taken from, we don't need to do anything - // otherwise, do the transfer if (targetModel != mSourceModel) diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp index 79951f70e..e32c6efaf 100644 --- a/apps/openmw/mwgui/container.hpp +++ b/apps/openmw/mwgui/container.hpp @@ -33,13 +33,14 @@ namespace MWGui public: bool mIsOnDragAndDrop; MyGUI::Widget* mDraggedWidget; - MyGUI::Widget* mDragAndDropWidget; ItemModel* mSourceModel; ItemView* mSourceView; SortFilterItemModel* mSourceSortModel; ItemStack mItem; int mDraggedCount; + DragAndDrop(); + void startDrag (int index, SortFilterItemModel* sortModel, ItemModel* sourceModel, ItemView* sourceView, int count); void drop (ItemModel* targetModel, ItemView* targetView); diff --git a/apps/openmw/mwgui/controllers.cpp b/apps/openmw/mwgui/controllers.cpp index e62fb3fce..a50e6496c 100644 --- a/apps/openmw/mwgui/controllers.cpp +++ b/apps/openmw/mwgui/controllers.cpp @@ -1,5 +1,7 @@ #include "controllers.hpp" +#include + namespace MWGui { namespace Controllers @@ -50,5 +52,17 @@ namespace MWGui { } + // ------------------------------------------------------------- + + void ControllerFollowMouse::prepareItem(MyGUI::Widget *_widget) + { + } + + bool ControllerFollowMouse::addTime(MyGUI::Widget *_widget, float _time) + { + _widget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + return true; + } + } } diff --git a/apps/openmw/mwgui/controllers.hpp b/apps/openmw/mwgui/controllers.hpp index 798acde62..937855606 100644 --- a/apps/openmw/mwgui/controllers.hpp +++ b/apps/openmw/mwgui/controllers.hpp @@ -40,6 +40,17 @@ namespace MWGui bool mEnabled; float mTimeLeft; }; + + /// Automatically positions a widget below the mouse cursor. + class ControllerFollowMouse : + public MyGUI::ControllerItem + { + MYGUI_RTTI_DERIVED( ControllerFollowMouse ) + + private: + bool addTime(MyGUI::Widget* _widget, float _time); + void prepareItem(MyGUI::Widget* _widget); + }; } } diff --git a/apps/openmw/mwgui/fontloader.cpp b/apps/openmw/mwgui/fontloader.cpp index 92d9a25b6..13f4e41f2 100644 --- a/apps/openmw/mwgui/fontloader.cpp +++ b/apps/openmw/mwgui/fontloader.cpp @@ -262,11 +262,32 @@ namespace MWGui // in the cp437 encoding of the font. Fall back to similar available characters. if (mEncoding == ToUTF8::CP437) { - std::multimap additional; + std::multimap additional; // additional.insert(std::make_pair(39, 0x2019)); // apostrophe additional.insert(std::make_pair(45, 0x2013)); // dash + additional.insert(std::make_pair(45, 0x2014)); // dash additional.insert(std::make_pair(34, 0x201D)); // right double quotation mark additional.insert(std::make_pair(34, 0x201C)); // left double quotation mark + additional.insert(std::make_pair(44, 0x201A)); + additional.insert(std::make_pair(44, 0x201E)); + additional.insert(std::make_pair(43, 0x2020)); + additional.insert(std::make_pair(94, 0x02C6)); + additional.insert(std::make_pair(37, 0x2030)); + additional.insert(std::make_pair(83, 0x0160)); + additional.insert(std::make_pair(60, 0x2039)); + additional.insert(std::make_pair(79, 0x0152)); + additional.insert(std::make_pair(90, 0x017D)); + additional.insert(std::make_pair(39, 0x2019)); + additional.insert(std::make_pair(126, 0x02DC)); + additional.insert(std::make_pair(84, 0x2122)); + additional.insert(std::make_pair(83, 0x0161)); + additional.insert(std::make_pair(62, 0x203A)); + additional.insert(std::make_pair(111, 0x0153)); + additional.insert(std::make_pair(122, 0x017E)); + additional.insert(std::make_pair(89, 0x0178)); + additional.insert(std::make_pair(156, 0x00A2)); + additional.insert(std::make_pair(46, 0x2026)); + for (std::multimap::iterator it = additional.begin(); it != additional.end(); ++it) { if (it->first != i) diff --git a/apps/openmw/mwgui/formatting.cpp b/apps/openmw/mwgui/formatting.cpp index 4d3d04ced..1dded94fe 100644 --- a/apps/openmw/mwgui/formatting.cpp +++ b/apps/openmw/mwgui/formatting.cpp @@ -406,7 +406,7 @@ namespace MWGui box->setTextAlign(mTextStyle.mTextAlign); box->setTextColour(mTextStyle.mColour); box->setFontName(mTextStyle.mFont); - box->setCaption(realText); + box->setCaption(MyGUI::TextIterator::toTagsString(realText)); box->setSize(box->getSize().width, box->getTextSize().height); mHeight += box->getTextSize().height; diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 3e753b7f9..3a9aa7dcd 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -59,7 +59,7 @@ namespace MWGui }; - HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) + HUD::HUD(int fpsLevel, DragAndDrop* dragAndDrop) : Layout("openmw_hud.layout") , mHealth(NULL) , mMagicka(NULL) @@ -97,7 +97,7 @@ namespace MWGui , mWeaponSpellTimer(0.f) , mDrowningFlashTheta(0.f) { - setCoord(0,0, width, height); + mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); // Energy bars getWidget(mHealthFrame, "HealthFrame"); @@ -405,11 +405,6 @@ namespace MWGui mDrowningFlashTheta += dt * Ogre::Math::TWO_PI; } - void HUD::onResChange(int width, int height) - { - setCoord(0, 0, width, height); - } - void HUD::setSelectedSpell(const std::string& spellId, int successChancePercent) { const ESM::Spell* spell = diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp index 56b0ef7b5..bf0419aae 100644 --- a/apps/openmw/mwgui/hud.hpp +++ b/apps/openmw/mwgui/hud.hpp @@ -15,7 +15,7 @@ namespace MWGui class HUD : public OEngine::GUI::Layout, public LocalMapBase { public: - HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); + HUD(int fpsLevel, DragAndDrop* dragAndDrop); virtual ~HUD(); void setValue (const std::string& id, const MWMechanics::DynamicStat& value); void setFPS(float fps); @@ -47,7 +47,6 @@ namespace MWGui void setCrosshairVisible(bool visible); void onFrame(float dt); - void onResChange(int width, int height); void setCellName(const std::string& cellName); diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index f6d6b8135..034163469 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -30,6 +30,8 @@ namespace MWGui , mProgress(0) , mVSyncWasEnabled(false) { + mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); + getWidget(mLoadingText, "LoadingText"); getWidget(mProgressBar, "ProgressBar"); @@ -56,13 +58,6 @@ namespace MWGui mBackgroundImage->setVisible(visible); } - void LoadingScreen::onResChange(int w, int h) - { - setCoord(0,0,w,h); - - mBackgroundImage->setCoord(MyGUI::IntCoord(0,0,w,h)); - } - void LoadingScreen::loadingOn() { // Early-out if already on diff --git a/apps/openmw/mwgui/loadingscreen.hpp b/apps/openmw/mwgui/loadingscreen.hpp index f198d625d..310a6df3c 100644 --- a/apps/openmw/mwgui/loadingscreen.hpp +++ b/apps/openmw/mwgui/loadingscreen.hpp @@ -35,8 +35,6 @@ namespace MWGui void setLoadingProgress (const std::string& stage, int depth, int current, int total); void loadingDone(); - void onResChange(int w, int h); - void updateWindow(Ogre::RenderWindow* rw) { mWindow = rw; } private: diff --git a/apps/openmw/mwgui/screenfader.cpp b/apps/openmw/mwgui/screenfader.cpp new file mode 100644 index 000000000..c27737285 --- /dev/null +++ b/apps/openmw/mwgui/screenfader.cpp @@ -0,0 +1,111 @@ +#include "screenfader.hpp" + +namespace MWGui +{ + + ScreenFader::ScreenFader() + : WindowBase("openmw_screen_fader.layout") + , mMode(FadingMode_In) + , mRemainingTime(0.f) + , mTargetTime(0.f) + , mTargetAlpha(0.f) + , mCurrentAlpha(0.f) + , mStartAlpha(0.f) + , mFactor(1.f) + { + mMainWidget->setSize(MyGUI::RenderManager::getInstance().getViewSize()); + + setVisible(false); + } + + void ScreenFader::update(float dt) + { + if (mRemainingTime > 0) + { + if (mMode == FadingMode_In) + { + mCurrentAlpha -= dt/mTargetTime * (mStartAlpha-mTargetAlpha); + if (mCurrentAlpha < mTargetAlpha) mCurrentAlpha = mTargetAlpha; + } + else if (mMode == FadingMode_Out) + { + mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha); + if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha; + } + + mRemainingTime -= dt; + } + + if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f) + mMainWidget->setVisible(false); + else + applyAlpha(); + } + + void ScreenFader::applyAlpha() + { + setVisible(true); + mMainWidget->setAlpha(1.f-((1.f-mCurrentAlpha) * mFactor)); + } + + void ScreenFader::fadeIn(float time) + { + if (time<0.f) return; + if (time==0.f) + { + mCurrentAlpha = 0.f; + applyAlpha(); + return; + } + + mStartAlpha = mCurrentAlpha; + mTargetAlpha = 0.f; + mMode = FadingMode_In; + mTargetTime = time; + mRemainingTime = time; + } + + void ScreenFader::fadeOut(const float time) + { + if (time<0.f) return; + if (time==0.f) + { + mCurrentAlpha = 1.f; + applyAlpha(); + return; + } + + mStartAlpha = mCurrentAlpha; + mTargetAlpha = 1.f; + mMode = FadingMode_Out; + mTargetTime = time; + mRemainingTime = time; + } + + void ScreenFader::fadeTo(const int percent, const float time) + { + if (time<0.f) return; + if (time==0.f) + { + mCurrentAlpha = percent/100.f; + applyAlpha(); + return; + } + + mStartAlpha = mCurrentAlpha; + mTargetAlpha = percent/100.f; + + if (mTargetAlpha == mStartAlpha) return; + else if (mTargetAlpha > mStartAlpha) mMode = FadingMode_Out; + else mMode = FadingMode_In; + + mTargetTime = time; + mRemainingTime = time; + } + + void ScreenFader::setFactor(float factor) + { + mFactor = factor; + } + +} diff --git a/apps/openmw/mwgui/screenfader.hpp b/apps/openmw/mwgui/screenfader.hpp new file mode 100644 index 000000000..0fb1f2794 --- /dev/null +++ b/apps/openmw/mwgui/screenfader.hpp @@ -0,0 +1,39 @@ +#include "windowbase.hpp" + +namespace MWGui +{ + + class ScreenFader : public WindowBase + { + public: + ScreenFader(); + + void update(float dt); + + void fadeIn(const float time); + void fadeOut(const float time); + void fadeTo(const int percent, const float time); + + void setFactor (float factor); + + private: + enum FadingMode + { + FadingMode_In, + FadingMode_Out + }; + + void applyAlpha(); + + FadingMode mMode; + + float mRemainingTime; + float mTargetTime; + float mTargetAlpha; + float mCurrentAlpha; + float mStartAlpha; + + float mFactor; + }; + +} diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index babfe099f..c93c73063 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -2,8 +2,6 @@ #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -171,7 +169,7 @@ namespace MWGui MWBase::Environment::get().getMechanicsManager()->rest(false); MWBase::Environment::get().getMechanicsManager()->rest(false); - MWBase::Environment::get().getWorld ()->getFader()->fadeOut(0.25); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.25); mFadeTimeRemaining = 0.5; } @@ -183,6 +181,6 @@ namespace MWGui mFadeTimeRemaining -= dt; if (mFadeTimeRemaining <= 0) - MWBase::Environment::get().getWorld ()->getFader()->fadeIn(0.25); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.25); } } diff --git a/apps/openmw/mwgui/travelwindow.cpp b/apps/openmw/mwgui/travelwindow.cpp index ae191e764..d874cecfe 100644 --- a/apps/openmw/mwgui/travelwindow.cpp +++ b/apps/openmw/mwgui/travelwindow.cpp @@ -4,8 +4,6 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" @@ -156,7 +154,7 @@ namespace MWGui MWMechanics::CreatureStats& npcStats = mPtr.getClass().getCreatureStats(mPtr); npcStats.setGoldPool(npcStats.getGoldPool() + price); - MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(1); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(1); ESM::Position pos = *_sender->getUserData(); std::string cellname = _sender->getUserString("Destination"); bool interior = _sender->getUserString("interior") == "y"; @@ -179,8 +177,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Travel); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Dialogue); - MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0); - MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(1); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(1); } void TravelWindow::onCancelButtonClicked(MyGUI::Widget* _sender) diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 9c7757af9..1f97e13f1 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -2,8 +2,6 @@ #include -#include - #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -128,7 +126,7 @@ namespace MWGui MWBase::Environment::get().getStateManager()->quickSave("Autosave"); MWBase::World* world = MWBase::Environment::get().getWorld(); - world->getFader ()->fadeOut(0.2); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.2); setVisible(false); mProgressBar.setVisible (true); @@ -243,7 +241,7 @@ namespace MWGui void WaitDialog::stopWaiting () { - MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.2); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.2); mProgressBar.setVisible (false); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_Rest); MWBase::Environment::get().getWindowManager()->removeGuiMode (GM_RestBed); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 5cd8899d8..da6065bac 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -65,6 +65,7 @@ #include "videowidget.hpp" #include "backgroundimage.hpp" #include "itemwidget.hpp" +#include "screenfader.hpp" namespace MWGui { @@ -112,6 +113,7 @@ namespace MWGui , mCompanionWindow(NULL) , mVideoBackground(NULL) , mVideoWidget(NULL) + , mScreenFader(NULL) , mTranslationDataStorage (translationDataStorage) , mCharGen(NULL) , mInputBlocker(NULL) @@ -171,18 +173,14 @@ namespace MWGui ItemWidget::registerComponents(); MyGUI::FactoryManager::getInstance().registerFactory("Controller"); + MyGUI::FactoryManager::getInstance().registerFactory("Controller"); MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); MyGUI::ResourceManager::getInstance().load("core.xml"); MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); - // Get size info from the Gui object - int w = MyGUI::RenderManager::getInstance().getViewSize().width; - int h = MyGUI::RenderManager::getInstance().getViewSize().height; - mLoadingScreen = new LoadingScreen(mRendering->getScene (), mRendering->getWindow ()); - mLoadingScreen->onResChange (w,h); //set up the hardware cursor manager mCursorManager = new SFO::SDLCursorManager(); @@ -192,7 +190,6 @@ namespace MWGui MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); - //SDL_ShowCursor(false); mCursorManager->setEnabled(true); @@ -217,13 +214,7 @@ namespace MWGui int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; - MyGUI::Widget* dragAndDropWidget = mGui->createWidgetT("Widget","",0,0,w,h,MyGUI::Align::Default,"DragAndDrop","DragAndDropWidget"); - dragAndDropWidget->setVisible(false); - mDragAndDrop = new DragAndDrop(); - mDragAndDrop->mIsOnDragAndDrop = false; - mDragAndDrop->mDraggedWidget = 0; - mDragAndDrop->mDragAndDropWidget = dragAndDropWidget; mRecharge = new Recharge(); mMenu = new MainMenu(w,h); @@ -245,7 +236,7 @@ namespace MWGui trackWindow(mDialogueWindow, "dialogue"); mContainerWindow = new ContainerWindow(mDragAndDrop); trackWindow(mContainerWindow, "container"); - mHud = new HUD(w,h, mShowFPSLevel, mDragAndDrop); + mHud = new HUD(mShowFPSLevel, mDragAndDrop); mToolTips = new ToolTips(); mScrollWindow = new ScrollWindow(); mBookWindow = new BookWindow(); @@ -267,8 +258,9 @@ namespace MWGui mSoulgemDialog = new SoulgemDialog(mMessageBoxManager); mCompanionWindow = new CompanionWindow(mDragAndDrop, mMessageBoxManager); trackWindow(mCompanionWindow, "companion"); + mScreenFader = new ScreenFader(); - mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Default,"Overlay"); + mInputBlocker = mGui->createWidget("",0,0,w,h,MyGUI::Align::Stretch,"Overlay"); mHud->setVisible(mHudEnabled); @@ -357,6 +349,7 @@ namespace MWGui delete mCursorManager; delete mRecharge; delete mCompanionWindow; + delete mScreenFader; cleanupGarbage(); @@ -858,6 +851,8 @@ namespace MWGui mCompanionWindow->checkReferenceAvailable(); mConsole->checkReferenceAvailable(); mCompanionWindow->onFrame(); + + mScreenFader->update(frameDuration); } void WindowManager::changeCell(MWWorld::CellStore* cell) @@ -1019,7 +1014,6 @@ namespace MWGui { sizeVideo(x, y); mGuiManager->windowResized(); - mLoadingScreen->onResChange (x,y); if (!mHud) return; // UI not initialized yet @@ -1033,7 +1027,6 @@ namespace MWGui it->first->setSize(size); } - mHud->onResChange(x, y); mConsole->onResChange(x, y); mMenu->onResChange(x, y); mSettingsWindow->center(); @@ -1042,8 +1035,6 @@ namespace MWGui mBookWindow->center(); mQuickKeysMenu->center(); mSpellBuyingWindow->center(); - mDragAndDrop->mDragAndDropWidget->setSize(MyGUI::IntSize(x, y)); - mInputBlocker->setSize(MyGUI::IntSize(x,y)); } void WindowManager::pushGuiMode(GuiMode mode) @@ -1688,4 +1679,24 @@ namespace MWGui updateVisible(); } + + void WindowManager::fadeScreenIn(const float time) + { + mScreenFader->fadeIn(time); + } + + void WindowManager::fadeScreenOut(const float time) + { + mScreenFader->fadeOut(time); + } + + void WindowManager::fadeScreenTo(const int percent, const float time) + { + mScreenFader->fadeTo(percent, time); + } + + void WindowManager::setScreenFactor(float factor) + { + mScreenFader->setFactor(factor); + } } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8093d637e..565e442f9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -86,6 +86,7 @@ namespace MWGui class CompanionWindow; class VideoWidget; class WindowModal; + class ScreenFader; class WindowManager : public MWBase::WindowManager { @@ -324,6 +325,15 @@ namespace MWGui virtual void pinWindow (MWGui::GuiWindow window); + /// Fade the screen in, over \a time seconds + virtual void fadeScreenIn(const float time); + /// Fade the screen out to black, over \a time seconds + virtual void fadeScreenOut(const float time); + /// Fade the screen to a specified percentage of black, over \a time seconds + virtual void fadeScreenTo(const int percent, const float time); + /// Darken the screen by \a factor (1.0 = no darkening). Works independently from screen fading. + virtual void setScreenFactor (float factor); + private: bool mConsoleOnlyScripts; @@ -373,6 +383,7 @@ namespace MWGui CompanionWindow* mCompanionWindow; MyGUI::ImageBox* mVideoBackground; VideoWidget* mVideoWidget; + ScreenFader* mScreenFader; Translation::Storage& mTranslationDataStorage; Cursor* mSoftwareCursor; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 067ad72bb..f60c89681 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -805,16 +805,16 @@ namespace MWInput if (MyGUI::InputManager::getInstance ().isModalAny()) return; - if((!MWBase::Environment::get().getWindowManager()->isGuiMode() - || MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Dialogue) - && MWBase::Environment::get().getWindowManager ()->getJournalAllowed()) + if(MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal + && MWBase::Environment::get().getWindowManager ()->getJournalAllowed() + && MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console) { MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal); } - else if(MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Journal) + else if(MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Journal)) { - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Journal); } } diff --git a/apps/openmw/mwmechanics/combat.cpp b/apps/openmw/mwmechanics/combat.cpp index c13eac98c..c04e2c62d 100644 --- a/apps/openmw/mwmechanics/combat.cpp +++ b/apps/openmw/mwmechanics/combat.cpp @@ -169,12 +169,12 @@ namespace MWMechanics MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker); - const MWWorld::Class &othercls = victim.getClass(); - if(!othercls.isActor()) // Can't hit non-actors - return; - MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim); - if(otherstats.isDead()) // Can't hit dead actors + if(victim.isEmpty() || !victim.getClass().isActor() || victim.getClass().getCreatureStats(victim).isDead()) + // Can't hit non-actors or dead actors + { + reduceWeaponCondition(0.f, false, weapon, attacker); return; + } if(attacker.getRefData().getHandle() == "player") MWBase::Environment::get().getWindowManager()->setEnemy(victim); @@ -189,6 +189,7 @@ namespace MWMechanics if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f) { victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false); + MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker); return; } @@ -209,6 +210,8 @@ namespace MWMechanics damage *= fDamageStrengthBase + (attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1); + adjustWeaponDamage(damage, weapon); + reduceWeaponCondition(damage, true, weapon, attacker); if(attacker.getRefData().getHandle() == "player") attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0); @@ -295,4 +298,42 @@ namespace MWMechanics } } + void reduceWeaponCondition(float damage, bool hit, MWWorld::Ptr &weapon, const MWWorld::Ptr &attacker) + { + if (weapon.isEmpty()) + return; + + if (!hit) + damage = 0.f; + + const bool weaphashealth = weapon.getClass().hasItemHealth(weapon); + if(weaphashealth) + { + int weaphealth = weapon.getClass().getItemHealth(weapon); + + const float fWeaponDamageMult = MWBase::Environment::get().getWorld()->getStore().get().find("fWeaponDamageMult")->getFloat(); + float x = std::max(1.f, fWeaponDamageMult * damage); + + weaphealth -= std::min(int(x), weaphealth); + weapon.getCellRef().setCharge(weaphealth); + + // Weapon broken? unequip it + if (weaphealth == 0) + weapon = *attacker.getClass().getInventoryStore(attacker).unequipItem(weapon, attacker); + } + } + + void adjustWeaponDamage(float &damage, const MWWorld::Ptr &weapon) + { + if (weapon.isEmpty()) + return; + + const bool weaphashealth = weapon.getClass().hasItemHealth(weapon); + if(weaphashealth) + { + int weaphealth = weapon.getClass().getItemHealth(weapon); + int weapmaxhealth = weapon.getClass().getItemMaxHealth(weapon); + damage *= (float(weaphealth) / weapmaxhealth); + } + } } diff --git a/apps/openmw/mwmechanics/combat.hpp b/apps/openmw/mwmechanics/combat.hpp index eb89cb820..0d3009510 100644 --- a/apps/openmw/mwmechanics/combat.hpp +++ b/apps/openmw/mwmechanics/combat.hpp @@ -13,6 +13,7 @@ bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage); /// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt +/// @note \a victim may be empty (e.g. for a hit on terrain), a non-actor (environment objects) or an actor void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile, const Ogre::Vector3& hitPosition); @@ -22,6 +23,15 @@ float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, in /// Applies damage to attacker based on the victim's elemental shields. void applyElementalShields(const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim); +/// @param damage Unmitigated weapon damage of the attack +/// @param hit Was the attack successful? +/// @param weapon The weapon used. +/// @note if the weapon is unequipped as result of condition damage, a new Ptr will be assigned to \a weapon. +void reduceWeaponCondition (float damage, bool hit, MWWorld::Ptr& weapon, const MWWorld::Ptr& attacker); + +/// Adjust weapon damage based on its condition. A used weapon will be less effective. +void adjustWeaponDamage (float& damage, const MWWorld::Ptr& weapon); + } #endif diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 199dc488d..ed21fa8a8 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -973,6 +973,9 @@ namespace MWMechanics if (!it->getClass().isNpc()) continue; + if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) + continue; + // Will the witness report the crime? if (it->getClass().getCreatureStats(*it).getAiSetting(CreatureStats::AI_Alarm).getBase() >= alarm) { @@ -1071,6 +1074,9 @@ namespace MWMechanics if (*it != victim && type == OT_Assault) aggression = iFightAttacking; + if (it->getClass().getCreatureStats(*it).getAiSequence().isInCombat(victim)) + continue; + if (it->getClass().isClass(*it, "guard")) { // Mark as Alarmed for dialogue @@ -1100,6 +1106,35 @@ namespace MWMechanics } } + void MechanicsManager::actorAttacked(const MWWorld::Ptr &ptr, const MWWorld::Ptr &attacker) + { + if (ptr == MWBase::Environment::get().getWorld()->getPlayerPtr()) + return; + + std::list followers = getActorsFollowing(attacker); + if (std::find(followers.begin(), followers.end(), ptr) != followers.end()) + { + ptr.getClass().getCreatureStats(ptr).friendlyHit(); + + if (ptr.getClass().getCreatureStats(ptr).getFriendlyHits() < 4) + return; + } + + // Attacking peaceful NPCs is a crime + if (ptr.getClass().isNpc() && !attacker.isEmpty() && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker) + && !isAggressive(ptr, attacker)) + commitCrime(attacker, ptr, MWBase::MechanicsManager::OT_Assault); + + if (!attacker.isEmpty() && (attacker.getClass().getCreatureStats(attacker).getAiSequence().isInCombat(ptr) + || attacker == MWBase::Environment::get().getWorld()->getPlayerPtr()) + && !ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat(attacker)) + { + // Attacker is in combat with us, but we are not in combat with the attacker yet. Time to fight back. + // Note: accidental or collateral damage attacks are ignored. + startCombat(ptr, attacker); + } + } + bool MechanicsManager::awarenessCheck(const MWWorld::Ptr &ptr, const MWWorld::Ptr &observer) { if (observer.getClass().getCreatureStats(observer).isDead()) diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 365e24067..7dbc6da74 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -119,6 +119,7 @@ namespace MWMechanics OffenseType type, int arg=0); virtual void reportCrime (const MWWorld::Ptr& ptr, const MWWorld::Ptr& victim, OffenseType type, int arg=0); + virtual void actorAttacked (const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); /// Utility to check if taking this item is illegal and calling commitCrime if so virtual void itemTaken (const MWWorld::Ptr& ptr, const MWWorld::Ptr& item, int count); /// Utility to check if opening (i.e. unlocking) this object is illegal and calling commitCrime if so diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 94b479007..025777d09 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -72,7 +72,7 @@ namespace MWMechanics return schoolSkillMap[school]; } - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool) + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) { CreatureStats& stats = actor.getClass().getCreatureStats(actor); @@ -123,14 +123,17 @@ namespace MWMechanics if (MWBase::Environment::get().getWorld()->getGodModeState() && actor.getRefData().getHandle() == "player") castChance = 100; - return std::max(0.f, std::min(100.f, castChance)); + if (!cap) + return std::max(0.f, castChance); + else + return std::max(0.f, std::min(100.f, castChance)); } - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool) + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool, bool cap) { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(spellId); - return getSpellSuccessChance(spell, actor, effectiveSchool); + return getSpellSuccessChance(spell, actor, effectiveSchool, cap); } @@ -184,6 +187,10 @@ namespace MWMechanics float resisted = 0; if (magicEffect->mData.mFlags & ESM::MagicEffect::Harmful) { + // Effects with no resistance attribute belonging to them can not be resisted + if (ESM::MagicEffect::getResistanceEffect(effectId) == -1) + return 0.f; + float resistance = getEffectResistanceAttribute(effectId, magicEffects); float willpower = stats.getAttribute(ESM::Attribute::Willpower).getModified(); @@ -191,12 +198,13 @@ namespace MWMechanics float x = (willpower + 0.1 * luck) * stats.getFatigueTerm(); // This makes spells that are easy to cast harder to resist and vice versa + float castChance = 100.f; if (spell != NULL && !caster.isEmpty() && caster.getClass().isActor()) { - float castChance = getSpellSuccessChance(spell, caster); - if (castChance > 0) - x *= 50 / castChance; + castChance = getSpellSuccessChance(spell, caster, NULL, false); // Uncapped casting chance } + if (castChance > 0) + x *= 50 / castChance; float roll = static_cast(std::rand()) / RAND_MAX * 100; if (magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude) @@ -230,6 +238,44 @@ namespace MWMechanics return -(resistance-100) / 100.f; } + /// Check if the given affect can be applied to the target. If \a castByPlayer, emits a message box on failure. + bool checkEffectTarget (int effectId, const MWWorld::Ptr& target, bool castByPlayer) + { + switch (effectId) + { + case ESM::MagicEffect::Levitate: + if (!MWBase::Environment::get().getWorld()->isLevitationEnabled()) + { + if (castByPlayer) + MWBase::Environment::get().getWindowManager()->messageBox("#{sLevitateDisabled}"); + return false; + } + break; + case ESM::MagicEffect::Soultrap: + if ((target.getClass().isActor() && target.getClass().isNpc()) + || (target.getTypeName() == typeid(ESM::Creature).name() && target.get()->mBase->mData.mSoul == 0)) + { + if (castByPlayer) + MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicInvalidTarget}"); + return false; + } + break; + case ESM::MagicEffect::AlmsiviIntervention: + case ESM::MagicEffect::DivineIntervention: + case ESM::MagicEffect::Mark: + case ESM::MagicEffect::Recall: + if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled()) + { + if (castByPlayer) + MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); + return false; + } + break; + } + + return true; + } + CastSpell::CastSpell(const MWWorld::Ptr &caster, const MWWorld::Ptr &target) : mCaster(caster) , mTarget(target) @@ -318,23 +364,8 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->getStore().get().find ( effectIt->mEffectID); - if (!MWBase::Environment::get().getWorld()->isLevitationEnabled() && effectIt->mEffectID == ESM::MagicEffect::Levitate) - { - if (castByPlayer) - MWBase::Environment::get().getWindowManager()->messageBox("#{sLevitateDisabled}"); - continue; - } - - if (!MWBase::Environment::get().getWorld()->isTeleportingEnabled() && - (effectIt->mEffectID == ESM::MagicEffect::AlmsiviIntervention || - effectIt->mEffectID == ESM::MagicEffect::DivineIntervention || - effectIt->mEffectID == ESM::MagicEffect::Mark || - effectIt->mEffectID == ESM::MagicEffect::Recall)) - { - if (castByPlayer) - MWBase::Environment::get().getWindowManager()->messageBox("#{sTeleportDisabled}"); + if (!checkEffectTarget(effectIt->mEffectID, target, castByPlayer)) continue; - } // If player is healing someone, show the target's HP bar if (castByPlayer && target != caster diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 2de187ae4..9381b605e 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -26,11 +26,12 @@ namespace MWMechanics * @param spell spell to cast * @param actor calculate spell success chance for this actor (depends on actor's skills) * @param effectiveSchool the spell's effective school (relevant for skill progress) will be written here - * @attention actor has to be an NPC and not a creature! - * @return success chance from 0 to 100 (in percent) + * @param cap cap the result to 100%? + * @note actor can be an NPC or a creature + * @return success chance from 0 to 100 (in percent), if cap=false then chance above 100 may be returned. */ - float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL); - float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL); + float getSpellSuccessChance (const ESM::Spell* spell, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true); + float getSpellSuccessChance (const std::string& spellId, const MWWorld::Ptr& actor, int* effectiveSchool = NULL, bool cap=true); int getSpellSchool(const std::string& spellId, const MWWorld::Ptr& actor); int getSpellSchool(const ESM::Spell* spell, const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 271cbbfe1..50dec8950 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -98,6 +98,7 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) return; Ogre::Image image; + tex->load(); tex->convertToImage(image); Ogre::DataStreamPtr encoded = image.encode("tga"); @@ -137,6 +138,7 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell) return; Ogre::Image image; + tex->load(); tex->convertToImage(image); fog->mFogTextures.push_back(ESM::FogTexture()); @@ -581,6 +583,8 @@ void LocalMap::updatePlayer (const Ogre::Vector3& position, const Ogre::Quaterni } } + tex->load(); + // copy to the texture // NOTE: Could be optimized later. We actually only need to update the region that changed. // Not a big deal at the moment, the FoW is only 32x32 anyway. diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 23edb3a7f..a1d34f12f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -212,11 +212,6 @@ MWRender::Actors& RenderingManager::getActors(){ return *mActors; } -OEngine::Render::Fader* RenderingManager::getFader() -{ - return mRendering.getFader(); -} - MWRender::Camera* RenderingManager::getCamera() const { return mCamera; @@ -345,7 +340,7 @@ void RenderingManager::update (float duration, bool paused) MWWorld::Ptr player = world->getPlayerPtr(); int blind = player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).mMagnitude; - mRendering.getFader()->setFactor(std::max(0.f, 1.f-(blind / 100.f))); + MWBase::Environment::get().getWindowManager()->setScreenFactor(std::max(0.f, 1.f-(blind / 100.f))); setAmbientMode(); // player position diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index ea7905cf5..ef436931d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -4,8 +4,6 @@ #include "sky.hpp" #include "debugging.hpp" -#include - #include #include @@ -98,8 +96,6 @@ public: void toggleLight(); bool toggleRenderMode(int mode); - OEngine::Render::Fader* getFader(); - void removeCell (MWWorld::CellStore *store); /// \todo this function should be removed later. Instead the rendering subsystems should track diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 8354cca5d..5b5a1594c 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -294,7 +294,12 @@ void SkyManager::create() // Stars mAtmosphereNight = mRootNode->createChildSceneNode(); - NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + NifOgre::ObjectScenePtr objects; + if (Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup("meshes\\sky_night_02.nif")) + objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_02.nif"); + else + objects = NifOgre::Loader::createObjects(mAtmosphereNight, "meshes\\sky_night_01.nif"); + for(size_t i = 0, matidx = 0;i < objects->mEntities.size();i++) { Entity* night1_ent = objects->mEntities[i]; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 36848d44c..b487ac70f 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -3,8 +3,6 @@ #include -#include - #include #include #include @@ -248,7 +246,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWorld()->getFader()->fadeIn(time); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(time); } }; @@ -261,7 +259,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWorld()->getFader()->fadeOut(time); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(time); } }; @@ -277,7 +275,7 @@ namespace MWScript Interpreter::Type_Float time = runtime[0].mFloat; runtime.pop(); - MWBase::Environment::get().getWorld()->getFader()->fadeTo(alpha, time); + MWBase::Environment::get().getWindowManager()->fadeScreenTo(alpha, time); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 07d137ce2..7150704ca 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -637,8 +637,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime); - std::string factionID = ""; if(arg0 >0) { @@ -647,6 +645,8 @@ namespace MWScript } else { + MWWorld::Ptr ptr = R()(runtime); + if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty()) { factionID = ""; @@ -913,8 +913,6 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime, unsigned int arg0) { - MWWorld::Ptr ptr = R()(runtime); - std::string factionID = ""; if(arg0 >0 ) { @@ -923,6 +921,8 @@ namespace MWScript } else { + MWWorld::Ptr ptr = R()(runtime); + if(ptr.getClass().getNpcStats(ptr).getFactionRanks().empty()) { factionID = ""; diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index a041049ca..528a6b9b9 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -327,7 +327,7 @@ namespace MWScript } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - ptr.getClass().adjustPosition(ptr); + ptr.getClass().adjustPosition(ptr, false); } else { @@ -374,7 +374,7 @@ namespace MWScript zRot = zRot/60.; } MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); - ptr.getClass().adjustPosition(ptr); + ptr.getClass().adjustPosition(ptr, false); } }; diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 446519b87..d241278d1 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -322,7 +322,7 @@ namespace MWWorld return std::make_pair (1, ""); } - void Class::adjustPosition(const MWWorld::Ptr& ptr) const + void Class::adjustPosition(const MWWorld::Ptr& ptr, bool force) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index e880030f9..64e83179d 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -90,8 +90,9 @@ namespace MWWorld ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. - virtual void adjustPosition(const MWWorld::Ptr& ptr) const; + virtual void adjustPosition(const MWWorld::Ptr& ptr, bool force) const; ///< Adjust position to stand on ground. Must be called post model load + /// @param force do this even if the ptr is flying virtual MWMechanics::CreatureStats& getCreatureStats (const Ptr& ptr) const; ///< Return creature stats or throw an exception, if class does not have creature stats diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index fb376bb93..ff1743c64 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -247,29 +247,23 @@ namespace MWWorld if (obstacle == caster) continue; - if (obstacle.isEmpty()) + MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); + + // Try to get a Ptr to the bow that was used. It might no longer exist. + MWWorld::Ptr bow = projectileRef.getPtr(); + if (!caster.isEmpty()) { - // Terrain - } - else if (obstacle.getClass().isActor()) - { - MWWorld::ManualRef projectileRef(MWBase::Environment::get().getWorld()->getStore(), it->mId); - - // Try to get a Ptr to the bow that was used. It might no longer exist. - MWWorld::Ptr bow = projectileRef.getPtr(); - if (!caster.isEmpty()) - { - MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); - MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); - if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) - bow = *invIt; - } - - if (caster.isEmpty()) - caster = obstacle; - - MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first); + MWWorld::InventoryStore& inv = caster.getClass().getInventoryStore(caster); + MWWorld::ContainerStoreIterator invIt = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); + if (invIt != inv.end() && Misc::StringUtils::ciEqual(invIt->getCellRef().getRefId(), it->mBowId)) + bow = *invIt; } + + if (caster.isEmpty()) + caster = obstacle; + + MWMechanics::projectileHit(caster, obstacle, bow, projectileRef.getPtr(), pos + (newPos - pos) * cIt->first); + hit = true; } if (hit) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index b2faa1a01..312fb9e36 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -4,8 +4,6 @@ #include -#include - #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" /// FIXME #include "../mwbase/soundmanager.hpp" @@ -86,7 +84,7 @@ namespace updateObjectLocalRotation(ptr, mPhysics, mRendering); MWBase::Environment::get().getWorld()->scaleObject (ptr, ptr.getCellRef().getScale()); - ptr.getClass().adjustPosition (ptr); + ptr.getClass().adjustPosition (ptr, false); } catch (const std::exception& e) { @@ -232,7 +230,7 @@ namespace MWWorld float z = Ogre::Radian(pos.rot[2]).valueDegrees(); world->rotateObject(player, x, y, z); - player.getClass().adjustPosition(player); + player.getClass().adjustPosition(player, true); } MWBase::MechanicsManager *mechMgr = @@ -406,7 +404,7 @@ namespace MWWorld void Scene::changeToInteriorCell (const std::string& cellName, const ESM::Position& position) { Nif::NIFFile::CacheLock lock; - MWBase::Environment::get().getWorld ()->getFader ()->fadeOut(0.5); + MWBase::Environment::get().getWindowManager()->fadeScreenOut(0.5); Loading::Listener* loadingListener = MWBase::Environment::get().getWindowManager()->getLoadingScreen(); Loading::ScopedLoad load(loadingListener); @@ -431,8 +429,8 @@ namespace MWWorld float z = Ogre::Radian(position.rot[2]).valueDegrees(); world->rotateObject(world->getPlayerPtr(), x, y, z); - world->getPlayerPtr().getClass().adjustPosition(world->getPlayerPtr()); - world->getFader()->fadeIn(0.5f); + world->getPlayerPtr().getClass().adjustPosition(world->getPlayerPtr(), true); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); return; } @@ -480,7 +478,7 @@ namespace MWWorld MWBase::Environment::get().getWorld()->adjustSky(); mCellChanged = true; - MWBase::Environment::get().getWorld ()->getFader ()->fadeIn(0.5); + MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); } void Scene::changeToExteriorCell (const ESM::Position& position) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f6aa6fec7..d57528864 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1151,7 +1151,7 @@ namespace MWWorld } } - void World::adjustPosition(const Ptr &ptr) + void World::adjustPosition(const Ptr &ptr, bool force) { ESM::Position pos (ptr.getRefData().getPosition()); @@ -1170,7 +1170,7 @@ namespace MWWorld ptr.getRefData().setPosition(pos); - if (!isFlying(ptr)) + if (force || !isFlying(ptr)) { Ogre::Vector3 traced = mPhysics->traceDown(ptr, 200); if (traced.z < pos.pos[2]) @@ -1555,11 +1555,6 @@ namespace MWWorld mWeatherManager->modRegion(regionid, chances); } - OEngine::Render::Fader* World::getFader() - { - return mRendering->getFader(); - } - Ogre::Vector2 World::getNorthVector (CellStore* cell) { MWWorld::CellRefList& statics = cell->get(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c4c8b588e..fad3dfd97 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -169,9 +169,6 @@ namespace MWWorld virtual void readRecord (ESM::ESMReader& reader, int32_t type, const std::map& contentFileMap); - virtual OEngine::Render::Fader* getFader(); - ///< \todo remove this function. Rendering details should not be exposed. - virtual CellStore *getExterior (int x, int y); virtual CellStore *getInterior (const std::string& name); @@ -260,8 +257,9 @@ namespace MWWorld virtual Ptr searchPtrViaActorId (int actorId); ///< Search is limited to the active cells. - virtual void adjustPosition (const Ptr& ptr); + virtual void adjustPosition (const Ptr& ptr, bool force); ///< Adjust position after load to be on ground. Must be called after model load. + /// @param force do this even if the ptr is flying virtual void fixPosition (const Ptr& actor); ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 1aa50249e..73877f459 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -113,7 +113,7 @@ namespace Compiler { void registerExtensions (Extensions& extensions) { - extensions.registerInstruction ("additem", "cl", opcodeAddItem, opcodeAddItemExplicit); + extensions.registerInstruction ("additem", "clX", opcodeAddItem, opcodeAddItemExplicit); extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount, opcodeGetItemCountExplicit); extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 2135f4dde..54a4d0b63 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -80,6 +80,7 @@ set(MYGUI_FILES openmw_companion_window.layout openmw_savegame_dialog.layout openmw_recharge_dialog.layout + openmw_screen_fader.layout DejaVuLGCSansMono.ttf markers.png ../launcher/images/openmw.png diff --git a/files/mygui/openmw_hud.layout b/files/mygui/openmw_hud.layout index e1f8af7bf..be3d17506 100644 --- a/files/mygui/openmw_hud.layout +++ b/files/mygui/openmw_hud.layout @@ -1,7 +1,7 @@ - + diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index e66f3fc01..1df4841af 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -1,6 +1,7 @@ + diff --git a/files/mygui/openmw_loading_screen.layout b/files/mygui/openmw_loading_screen.layout index faa0d8637..eda002040 100644 --- a/files/mygui/openmw_loading_screen.layout +++ b/files/mygui/openmw_loading_screen.layout @@ -2,7 +2,7 @@ - + diff --git a/files/mygui/openmw_screen_fader.layout b/files/mygui/openmw_screen_fader.layout new file mode 100644 index 000000000..fffd2e66e --- /dev/null +++ b/files/mygui/openmw_screen_fader.layout @@ -0,0 +1,7 @@ + + + + + + + diff --git a/libs/openengine/ogre/fader.cpp b/libs/openengine/ogre/fader.cpp deleted file mode 100644 index 20b9296da..000000000 --- a/libs/openengine/ogre/fader.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "fader.hpp" - -#include -#include -#include -#include -#include -#include -#include - - -using namespace Ogre; -using namespace OEngine::Render; - -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) - , mFactor(1.f) -{ - // Create the fading material - MaterialPtr material = MaterialManager::getSingleton().create("FadeInOutMaterial", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); - Pass* pass = material->getTechnique(0)->getPass(0); - pass->setSceneBlending(SBT_TRANSPARENT_ALPHA); - pass->setDepthWriteEnabled (false); - mFadeTextureUnit = pass->createTextureUnitState("black.png"); - mFadeTextureUnit->setColourOperationEx(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, ColourValue(0.f, 0.f, 0.f)); // always black colour - - 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 (2048); -} - -Fader::~Fader() -{ - delete mRectangle; -} - -void Fader::update(float dt) -{ - if (mRemainingTime > 0) - { - if (mMode == FadingMode_In) - { - mCurrentAlpha -= dt/mTargetTime * (mStartAlpha-mTargetAlpha); - if (mCurrentAlpha < mTargetAlpha) mCurrentAlpha = mTargetAlpha; - } - else if (mMode == FadingMode_Out) - { - mCurrentAlpha += dt/mTargetTime * (mTargetAlpha-mStartAlpha); - if (mCurrentAlpha > mTargetAlpha) mCurrentAlpha = mTargetAlpha; - } - - mRemainingTime -= dt; - } - - if (1.f-((1.f-mCurrentAlpha) * mFactor) == 0.f) - mRectangle->setVisible(false); - else - applyAlpha(); -} - -void Fader::applyAlpha() -{ - mRectangle->setVisible(true); - mFadeTextureUnit->setAlphaOperation(LBX_SOURCE1, LBS_MANUAL, LBS_CURRENT, 1.f-((1.f-mCurrentAlpha) * mFactor)); -} - -void Fader::fadeIn(float time) -{ - if (time<0.f) return; - if (time==0.f) - { - mCurrentAlpha = 0.f; - applyAlpha(); - return; - } - - mStartAlpha = mCurrentAlpha; - mTargetAlpha = 0.f; - mMode = FadingMode_In; - mTargetTime = time; - mRemainingTime = time; -} - -void Fader::fadeOut(const float time) -{ - if (time<0.f) return; - if (time==0.f) - { - mCurrentAlpha = 1.f; - applyAlpha(); - return; - } - - mStartAlpha = mCurrentAlpha; - mTargetAlpha = 1.f; - mMode = FadingMode_Out; - mTargetTime = time; - mRemainingTime = time; -} - -void Fader::fadeTo(const int percent, const float time) -{ - if (time<0.f) return; - if (time==0.f) - { - mCurrentAlpha = percent/100.f; - applyAlpha(); - return; - } - - mStartAlpha = mCurrentAlpha; - mTargetAlpha = percent/100.f; - - if (mTargetAlpha == mStartAlpha) return; - else if (mTargetAlpha > mStartAlpha) mMode = FadingMode_Out; - else mMode = FadingMode_In; - - mTargetTime = time; - mRemainingTime = time; -} diff --git a/libs/openengine/ogre/fader.hpp b/libs/openengine/ogre/fader.hpp deleted file mode 100644 index 53124e2f6..000000000 --- a/libs/openengine/ogre/fader.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef OENGINE_OGRE_FADE_H -#define OENGINE_OGRE_FADE_H - -/* - A class that handles fading in the screen from black or fading it out to black. - - To achieve this, it uses a full-screen Rectangle2d - */ - -namespace Ogre -{ - class TextureUnitState; - class Rectangle2D; - class SceneManager; -} - -namespace OEngine { -namespace Render -{ - class Fader - { - 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); - - void setFactor (float factor) { mFactor = factor; } - - 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; - - float mFactor; - - Ogre::SceneManager* mSceneMgr; - }; - }} -#endif diff --git a/libs/openengine/ogre/renderer.cpp b/libs/openengine/ogre/renderer.cpp index 8fcf615ba..78eff6aee 100644 --- a/libs/openengine/ogre/renderer.cpp +++ b/libs/openengine/ogre/renderer.cpp @@ -1,5 +1,4 @@ #include "renderer.hpp" -#include "fader.hpp" #include @@ -27,9 +26,6 @@ using namespace OEngine::Render; void OgreRenderer::cleanup() { - delete mFader; - mFader = NULL; - if (mWindow) Ogre::Root::getSingleton().destroyRenderTarget(mWindow); mWindow = NULL; @@ -46,7 +42,6 @@ void OgreRenderer::cleanup() void OgreRenderer::update(float dt) { - mFader->update(dt); } void OgreRenderer::screenshot(const std::string &file) @@ -161,8 +156,6 @@ void OgreRenderer::createWindow(const std::string &title, const WindowSettings& mScene = mRoot->createSceneManager(ST_GENERIC); - mFader = new Fader(mScene); - mCamera = mScene->createCamera("cam"); // Create one viewport, entire window diff --git a/libs/openengine/ogre/renderer.hpp b/libs/openengine/ogre/renderer.hpp index ad88b1606..c7ec2ec44 100644 --- a/libs/openengine/ogre/renderer.hpp +++ b/libs/openengine/ogre/renderer.hpp @@ -43,8 +43,6 @@ namespace OEngine std::string icon; }; - class Fader; - class WindowSizeListener { public: @@ -62,8 +60,6 @@ namespace OEngine OgreInit::OgreInit* mOgreInit; - Fader* mFader; - WindowSizeListener* mWindowListener; int mWindowWidth; @@ -79,7 +75,6 @@ namespace OEngine , mCamera(NULL) , mView(NULL) , mOgreInit(NULL) - , mFader(NULL) , mWindowListener(NULL) , mWindowWidth(0) , mWindowHeight(0) @@ -131,9 +126,6 @@ namespace OEngine /// Get the scene manager Ogre::SceneManager *getScene() { return mScene; } - /// Get the screen colour fader - Fader *getFader() { return mFader; } - /// Camera Ogre::Camera *getCamera() { return mCamera; }