diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ca2355346c..45ce1b9af8 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -23,10 +23,10 @@ add_openmw_dir (mwinput ) add_openmw_dir (mwgui - layouts text_input widgets race class birth review window_manager console dialogue + text_input widgets race class birth review window_manager console dialogue dialogue_history window_base stats_window messagebox journalwindow charactercreation map_window window_pinnable_base cursorreplace tooltips scrollwindow bookwindow list - formatting + formatting itemwidget inventorywindow container hud countdialog tradewindow ) add_openmw_dir (mwdialogue @@ -47,8 +47,8 @@ add_openmw_dir (mwsound add_openmw_dir (mwworld refdata world physicssystem scene globals class action nullaction actionteleport containerstore actiontalk actiontake manualref player cellfunctors - cells localscripts customdata weather inventorystore ptr actionread - timestamp + cells localscripts customdata weather inventorystore ptr actionopen actionread + actionequip timestamp ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index 6faaacf319..505f61f4ca 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -79,7 +79,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); std::string text; if (MWBase::Environment::get().getWindowManager()->getFullHelp()) diff --git a/apps/openmw/mwclass/apparatus.cpp b/apps/openmw/mwclass/apparatus.cpp index 215183dca7..0ce01024db 100644 --- a/apps/openmw/mwclass/apparatus.cpp +++ b/apps/openmw/mwclass/apparatus.cpp @@ -100,6 +100,14 @@ namespace MWClass return std::string("Item Apparatus Down"); } + std::string Apparatus::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Apparatus::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -114,7 +122,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/apparatus.hpp b/apps/openmw/mwclass/apparatus.hpp index e99ea1c1d3..d281600beb 100644 --- a/apps/openmw/mwclass/apparatus.hpp +++ b/apps/openmw/mwclass/apparatus.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 87a5dde27a..83c0120c78 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -198,6 +199,14 @@ namespace MWClass return std::string("Item Armor Heavy Down"); } + std::string Armor::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Armor::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -212,7 +221,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; std::string text; @@ -256,4 +265,11 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Armor::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/armor.hpp b/apps/openmw/mwclass/armor.hpp index 3ff101a5e5..a638061625 100644 --- a/apps/openmw/mwclass/armor.hpp +++ b/apps/openmw/mwclass/armor.hpp @@ -56,8 +56,16 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu + }; } diff --git a/apps/openmw/mwclass/book.cpp b/apps/openmw/mwclass/book.cpp index 2409f95e45..a107d9b210 100644 --- a/apps/openmw/mwclass/book.cpp +++ b/apps/openmw/mwclass/book.cpp @@ -97,6 +97,14 @@ namespace MWClass return std::string("Item Book Down"); } + std::string Book::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Book::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -111,7 +119,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); @@ -132,4 +140,18 @@ namespace MWClass return info; } + + std::string Book::getEnchantment (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->enchant; + } + + boost::shared_ptr Book::use (const MWWorld::Ptr& ptr) const + { + return boost::shared_ptr(new MWWorld::ActionRead(ptr)); + } + } diff --git a/apps/openmw/mwclass/book.hpp b/apps/openmw/mwclass/book.hpp index e85fbfb7f9..ee3aac8d81 100644 --- a/apps/openmw/mwclass/book.hpp +++ b/apps/openmw/mwclass/book.hpp @@ -41,6 +41,15 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. + + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; + ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwclass/clothing.cpp b/apps/openmw/mwclass/clothing.cpp index a242874df3..11b515faf7 100644 --- a/apps/openmw/mwclass/clothing.cpp +++ b/apps/openmw/mwclass/clothing.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -166,6 +167,14 @@ namespace MWClass return std::string("Item Clothes Down"); } + std::string Clothing::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Clothing::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -180,7 +189,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); @@ -209,4 +218,11 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Clothing::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/clothing.hpp b/apps/openmw/mwclass/clothing.hpp index 9b9322969a..aba317be0e 100644 --- a/apps/openmw/mwclass/clothing.hpp +++ b/apps/openmw/mwclass/clothing.hpp @@ -50,8 +50,15 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu }; } diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 34d6b6c60e..e9b8ce31fc 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -17,6 +17,7 @@ #include "../mwgui/tooltips.hpp" #include "../mwrender/objects.hpp" +#include "../mwworld/actionopen.hpp" #include "../mwsound/soundmanager.hpp" @@ -86,6 +87,7 @@ namespace MWClass const std::string lockedSound = "LockedChest"; const std::string trapActivationSound = "Disarm Trap Fail"; + if (ptr.getCellRef().lockLevel>0) { // TODO check for key @@ -99,7 +101,8 @@ namespace MWClass if(ptr.getCellRef().trap.empty()) { // Not trapped, Inventory GUI goes here - return boost::shared_ptr (new MWWorld::NullAction); + //return boost::shared_ptr (new MWWorld::NullAction); + return boost::shared_ptr (new MWWorld::ActionOpen(ptr)); } else { @@ -177,7 +180,7 @@ namespace MWClass return info; } - float Container::getCapactiy (const MWWorld::Ptr& ptr) const + float Container::getCapacity (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 61a0d912bc..44f0fe927b 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -36,7 +36,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index c2623500d8..653fabd089 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -166,7 +166,7 @@ namespace MWClass return info; } - float Creature::getCapactiy (const MWWorld::Ptr& ptr) const + float Creature::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); return stats.mAttributes[0].getModified()*5; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index 7224d3ee13..9d94915795 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -52,7 +52,7 @@ namespace MWClass virtual std::string getScript (const MWWorld::Ptr& ptr) const; ///< Return name of the script attached to ptr - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwclass/ingredient.cpp b/apps/openmw/mwclass/ingredient.cpp index 068ae0cde2..c0186da37a 100644 --- a/apps/openmw/mwclass/ingredient.cpp +++ b/apps/openmw/mwclass/ingredient.cpp @@ -98,6 +98,14 @@ namespace MWClass return std::string("Item Ingredient Down"); } + std::string Ingredient::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Ingredient::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -112,7 +120,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/ingredient.hpp b/apps/openmw/mwclass/ingredient.hpp index 36756b6c33..4c45bd69c3 100644 --- a/apps/openmw/mwclass/ingredient.hpp +++ b/apps/openmw/mwclass/ingredient.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 0c6892d247..d9af2e73f3 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -140,6 +140,15 @@ namespace MWClass return std::string("Item Misc Down"); } + + std::string Light::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Light::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -154,7 +163,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 7149a41a9c..4f21a0f8e1 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -50,6 +50,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/lockpick.cpp b/apps/openmw/mwclass/lockpick.cpp index bd5849f669..5bb6776465 100644 --- a/apps/openmw/mwclass/lockpick.cpp +++ b/apps/openmw/mwclass/lockpick.cpp @@ -110,6 +110,14 @@ namespace MWClass return std::string("Item Lockpick Down"); } + std::string Lockpick::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Lockpick::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -124,7 +132,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/lockpick.hpp b/apps/openmw/mwclass/lockpick.hpp index 0eaaa5af9b..b8683c5e99 100644 --- a/apps/openmw/mwclass/lockpick.hpp +++ b/apps/openmw/mwclass/lockpick.hpp @@ -45,6 +45,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/misc.cpp b/apps/openmw/mwclass/misc.cpp index facee1bbbe..d8e0553b9e 100644 --- a/apps/openmw/mwclass/misc.cpp +++ b/apps/openmw/mwclass/misc.cpp @@ -1,6 +1,8 @@ #include "misc.hpp" +#include + #include #include @@ -116,6 +118,14 @@ namespace MWClass return std::string("Item Misc Down"); } + std::string Miscellaneous::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Miscellaneous::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -130,11 +140,24 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; - info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); + int count = ptr.getRefData().getCount(); + + bool isGold = (ref->base->name == store.gameSettings.search("sGold")->str); + if (isGold && count == 1) + count = ref->base->data.value; + + std::string countString; + if (!isGold) + countString = MWGui::ToolTips::getCountString(count); + else // gold displays its count also if it's 1. + countString = " (" + boost::lexical_cast(count) + ")"; + + info.caption = ref->base->name + countString; + info.icon = ref->base->icon; + if (ref->ref.soul != "") { const ESM::Creature *creature = store.creatures.search(ref->ref.soul); @@ -143,9 +166,7 @@ namespace MWClass std::string text; - if (ref->base->name == store.gameSettings.search("sGold")->str) - info.caption += " (" + boost::lexical_cast(ref->base->data.value) + ")"; - else + if (!isGold) { text += "\n" + store.gameSettings.search("sWeight")->str + ": " + MWGui::ToolTips::toString(ref->base->data.weight); text += MWGui::ToolTips::getValueString(ref->base->data.value, store.gameSettings.search("sValue")->str); diff --git a/apps/openmw/mwclass/misc.hpp b/apps/openmw/mwclass/misc.hpp index fbe721cf3d..46b5b9662d 100644 --- a/apps/openmw/mwclass/misc.hpp +++ b/apps/openmw/mwclass/misc.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 556798bf44..e7f6cc5270 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -3,6 +3,8 @@ #include +#include + #include #include @@ -56,13 +58,15 @@ namespace MWClass // NPC stats if (!ref->base->faction.empty()) { + std::string faction = ref->base->faction; + boost::algorithm::to_lower(faction); if(ref->base->npdt52.gold != -10) { - data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt52.rank; + data->mNpcStats.mFactionRank[faction] = (int)ref->base->npdt52.rank; } else { - data->mNpcStats.mFactionRank[ref->base->faction] = (int)ref->base->npdt12.rank; + data->mNpcStats.mFactionRank[faction] = (int)ref->base->npdt12.rank; } } @@ -324,7 +328,7 @@ namespace MWClass return info; } - float Npc::getCapactiy (const MWWorld::Ptr& ptr) const + float Npc::getCapacity (const MWWorld::Ptr& ptr) const { const MWMechanics::CreatureStats& stats = getCreatureStats (ptr); return stats.mAttributes[0].getModified()*5; diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index 0cfad0347c..ef154bad41 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -74,7 +74,7 @@ namespace MWClass ///< Return desired movement vector (determined based on movement settings, /// stance and stats). - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. diff --git a/apps/openmw/mwclass/potion.cpp b/apps/openmw/mwclass/potion.cpp index 07e7663b38..ffc8386396 100644 --- a/apps/openmw/mwclass/potion.cpp +++ b/apps/openmw/mwclass/potion.cpp @@ -100,6 +100,14 @@ namespace MWClass return std::string("Item Potion Down"); } + std::string Potion::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Potion::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -114,7 +122,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/potion.hpp b/apps/openmw/mwclass/potion.hpp index 8c2357fb2e..74779864a1 100644 --- a/apps/openmw/mwclass/potion.hpp +++ b/apps/openmw/mwclass/potion.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/probe.cpp b/apps/openmw/mwclass/probe.cpp index 02dc1115d2..1e713f0a5d 100644 --- a/apps/openmw/mwclass/probe.cpp +++ b/apps/openmw/mwclass/probe.cpp @@ -109,6 +109,14 @@ namespace MWClass return std::string("Item Probe Down"); } + std::string Probe::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Probe::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -123,7 +131,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); diff --git a/apps/openmw/mwclass/probe.hpp b/apps/openmw/mwclass/probe.hpp index f8c13fa1ea..5e0059e141 100644 --- a/apps/openmw/mwclass/probe.hpp +++ b/apps/openmw/mwclass/probe.hpp @@ -45,6 +45,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/repair.cpp b/apps/openmw/mwclass/repair.cpp index 0eb1f0cf2a..5666a95a50 100644 --- a/apps/openmw/mwclass/repair.cpp +++ b/apps/openmw/mwclass/repair.cpp @@ -99,6 +99,14 @@ namespace MWClass return std::string("Item Repair Down"); } + std::string Repair::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Repair::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -113,7 +121,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; std::string text; diff --git a/apps/openmw/mwclass/repair.hpp b/apps/openmw/mwclass/repair.hpp index 1d9ebb8bfb..1e935e1543 100644 --- a/apps/openmw/mwclass/repair.hpp +++ b/apps/openmw/mwclass/repair.hpp @@ -41,6 +41,9 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. }; } diff --git a/apps/openmw/mwclass/weapon.cpp b/apps/openmw/mwclass/weapon.cpp index 0ddf19d3cc..482d618b01 100644 --- a/apps/openmw/mwclass/weapon.cpp +++ b/apps/openmw/mwclass/weapon.cpp @@ -9,6 +9,7 @@ #include "../mwworld/ptr.hpp" #include "../mwworld/actiontake.hpp" +#include "../mwworld/actionequip.hpp" #include "../mwworld/inventorystore.hpp" #include "../mwworld/world.hpp" @@ -250,6 +251,14 @@ namespace MWClass return std::string("Item Misc Down"); } + std::string Weapon::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + ESMS::LiveCellRef *ref = + ptr.get(); + + return ref->base->icon; + } + bool Weapon::hasToolTip (const MWWorld::Ptr& ptr) const { ESMS::LiveCellRef *ref = @@ -264,7 +273,7 @@ namespace MWClass ptr.get(); MWGui::ToolTipInfo info; - info.caption = ref->base->name; + info.caption = ref->base->name + MWGui::ToolTips::getCountString(ptr.getRefData().getCount()); info.icon = ref->base->icon; const ESMS::ESMStore& store = MWBase::Environment::get().getWorld()->getStore(); @@ -347,4 +356,11 @@ namespace MWClass return ref->base->enchant; } + + boost::shared_ptr Weapon::use (const MWWorld::Ptr& ptr) const + { + MWBase::Environment::get().getSoundManager()->playSound (getUpSoundId(ptr), 1.0, 1.0); + + return boost::shared_ptr(new MWWorld::ActionEquip(ptr)); + } } diff --git a/apps/openmw/mwclass/weapon.hpp b/apps/openmw/mwclass/weapon.hpp index c27a39620d..92d703b4ae 100644 --- a/apps/openmw/mwclass/weapon.hpp +++ b/apps/openmw/mwclass/weapon.hpp @@ -56,8 +56,16 @@ namespace MWClass virtual std::string getDownSoundId (const MWWorld::Ptr& ptr) const; ///< Return the put down sound Id + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string + + virtual boost::shared_ptr use (const MWWorld::Ptr& ptr) + const; + ///< Generate action for using via inventory menu + }; } diff --git a/apps/openmw/mwdialogue/dialoguemanager.cpp b/apps/openmw/mwdialogue/dialoguemanager.cpp index 295a50526e..af589469e7 100644 --- a/apps/openmw/mwdialogue/dialoguemanager.cpp +++ b/apps/openmw/mwdialogue/dialoguemanager.cpp @@ -206,7 +206,7 @@ namespace MWDialogue if(!NPCstats.mFactionRank.empty()) { std::string NPCFaction = NPCstats.mFactionRank.begin()->first; - if(PCstats.mFactionRank.find(NPCFaction) != PCstats.mFactionRank.end()) sameFaction = 1; + if(PCstats.mFactionRank.find(toLower(NPCFaction)) != PCstats.mFactionRank.end()) sameFaction = 1; } if(!selectCompare(comp,sameFaction,select.i)) return false; } @@ -525,7 +525,7 @@ namespace MWDialogue //MWWorld::Class npcClass = MWWorld::Class::get(actor); MWMechanics::NpcStats stats = MWWorld::Class::get(actor).getNpcStats(actor); - std::map::iterator it = stats.mFactionRank.find(info.npcFaction); + std::map::iterator it = stats.mFactionRank.find(toLower(info.npcFaction)); if(it!=stats.mFactionRank.end()) { //check rank @@ -542,7 +542,7 @@ namespace MWDialogue if(!info.pcFaction.empty()) { MWMechanics::NpcStats stats = MWWorld::Class::get(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()).getNpcStats(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - std::map::iterator it = stats.mFactionRank.find(info.pcFaction); + std::map::iterator it = stats.mFactionRank.find(toLower(info.pcFaction)); if(it!=stats.mFactionRank.end()) { //check rank @@ -637,7 +637,7 @@ namespace MWDialogue //initialise the GUI MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Dialogue); MWGui::DialogueWindow* win = MWBase::Environment::get().getWindowManager()->getDialogueWindow(); - win->startDialogue(MWWorld::Class::get (actor).getName (actor)); + win->startDialogue(actor, MWWorld::Class::get (actor).getName (actor)); //setup the list of topics known by the actor. Topics who are also on the knownTopics list will be added to the GUI updateTopics(); @@ -767,6 +767,36 @@ namespace MWDialogue } } + // check the available services of this actor + int services = 0; + if (mActor.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mActor.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + else if (mActor.getTypeName() == typeid(ESM::Creature).name()) + { + ESMS::LiveCellRef* ref = mActor.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + + if (services & ESM::NPC::Weapon + || services & ESM::NPC::Armor + || services & ESM::NPC::Clothing + || services & ESM::NPC::Books + || services & ESM::NPC::Ingredients + || services & ESM::NPC::Picks + || services & ESM::NPC::Probes + || services & ESM::NPC::Lights + || services & ESM::NPC::Apparatus + || services & ESM::NPC::RepairItem + || services & ESM::NPC::Misc) + win->setShowTrade(true); + else + win->setShowTrade(false); + // sort again, because the previous sort was case-sensitive keywordList.sort(stringCompareNoCase); win->setKeywords(keywordList); diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index cb15eaf15b..49f90d1a07 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -27,7 +27,6 @@ BirthDialog::BirthDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); MyGUI::ButtonPtr okButton; diff --git a/apps/openmw/mwgui/bookwindow.cpp b/apps/openmw/mwgui/bookwindow.cpp index 8de45984cd..c6411175d1 100644 --- a/apps/openmw/mwgui/bookwindow.cpp +++ b/apps/openmw/mwgui/bookwindow.cpp @@ -52,7 +52,7 @@ void BookWindow::open (MWWorld::Ptr book) clearPages(); mCurrentPage = 0; - MWBase::Environment::get().getSoundManager()->playSound3D (book, "book open", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("book open", 1.0, 1.0); ESMS::LiveCellRef *ref = mBook.get(); @@ -77,18 +77,26 @@ void BookWindow::open (MWWorld::Ptr book) } updatePages(); + + setTakeButtonShow(true); +} + +void BookWindow::setTakeButtonShow(bool show) +{ + mTakeButton->setVisible(show); } void BookWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mBook, "book close", 1.0, 1.0); + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("book close", 1.0, 1.0); MWBase::Environment::get().getInputManager()->setGuiMode(MWGui::GM_Game); } void BookWindow::onTakeButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mBook, "Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); MWWorld::ActionTake take(mBook); take.execute(); diff --git a/apps/openmw/mwgui/bookwindow.hpp b/apps/openmw/mwgui/bookwindow.hpp index fcea1d11f2..9ea0114338 100644 --- a/apps/openmw/mwgui/bookwindow.hpp +++ b/apps/openmw/mwgui/bookwindow.hpp @@ -11,7 +11,9 @@ namespace MWGui { public: BookWindow(WindowManager& parWindowManager); + void open(MWWorld::Ptr book); + void setTakeButtonShow(bool show); protected: void onNextPageButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 7a86ba9ac8..afb168d321 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -173,7 +173,6 @@ void CharacterCreation::spawnDialog(const char id) mWM->removeDialog(mBirthSignDialog); mBirthSignDialog = new BirthDialog(*mWM); mBirthSignDialog->setNextButtonShow(mCreationStage >= CSE_BirthSignChosen); - mBirthSignDialog->setBirthId(mPlayerBirthSignId); mBirthSignDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogDone); mBirthSignDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onBirthSignDialogBack); mBirthSignDialog->open(); @@ -414,7 +413,6 @@ void CharacterCreation::onBirthSignDialogDone(WindowBase* parWindow) if (mBirthSignDialog) { mPlayerBirthSignId = mBirthSignDialog->getBirthId(); - mWM->setBirthSign(mPlayerBirthSignId); if (!mPlayerBirthSignId.empty()) MWBase::Environment::get().getMechanicsManager()->setPlayerBirthsign(mPlayerBirthSignId); mWM->removeDialog(mBirthSignDialog); diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index e654f7c908..3e41fa6b10 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -28,7 +28,6 @@ GenerateClassResultDialog::GenerateClassResultDialog(WindowManager& parWindowMan MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &GenerateClassResultDialog::onBackClicked); MyGUI::ButtonPtr okButton; @@ -111,7 +110,6 @@ PickClassDialog::PickClassDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); @@ -432,7 +430,6 @@ CreateClassDialog::CreateClassDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); MyGUI::ButtonPtr okButton; getWidget(okButton, "OKButton"); diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 0e3348086d..6f0138aa4d 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -34,7 +34,7 @@ namespace MWGui typedef delegates::CMultiDelegate1 EventHandle_Int; /** Event : Button was clicked.\n - signature : void method(MyGUI::WidgetPtr widget, int index)\n + signature : void method(int index)\n */ EventHandle_Int eventButtonSelected; diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp new file mode 100644 index 0000000000..be21987ef9 --- /dev/null +++ b/apps/openmw/mwgui/container.cpp @@ -0,0 +1,672 @@ +#include "container.hpp" + +#include +#include +#include +#include +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/player.hpp" +#include "../mwclass/container.hpp" +#include "../mwinput/inputmanager.hpp" +#include "../mwsound/soundmanager.hpp" + +#include "window_manager.hpp" +#include "widgets.hpp" +#include "countdialog.hpp" +#include "tradewindow.hpp" +#include "inventorywindow.hpp" + +using namespace MWGui; +using namespace Widgets; + + +namespace +{ + bool compareType(std::string type1, std::string type2) + { + // this defines the sorting order of types. types that are first in the vector, appear before other types. + std::vector mapping; + mapping.push_back( typeid(ESM::Weapon).name() ); + mapping.push_back( typeid(ESM::Armor).name() ); + mapping.push_back( typeid(ESM::Clothing).name() ); + mapping.push_back( typeid(ESM::Potion).name() ); + mapping.push_back( typeid(ESM::Ingredient).name() ); + mapping.push_back( typeid(ESM::Apparatus).name() ); + mapping.push_back( typeid(ESM::Book).name() ); + mapping.push_back( typeid(ESM::Light).name() ); + mapping.push_back( typeid(ESM::Miscellaneous).name() ); + mapping.push_back( typeid(ESM::Tool).name() ); + mapping.push_back( typeid(ESM::Repair).name() ); + mapping.push_back( typeid(ESM::Probe).name() ); + + assert( std::find(mapping.begin(), mapping.end(), type1) != mapping.end() ); + assert( std::find(mapping.begin(), mapping.end(), type2) != mapping.end() ); + + return std::find(mapping.begin(), mapping.end(), type1) < std::find(mapping.begin(), mapping.end(), type2); + } + + bool sortItems(MWWorld::Ptr left, MWWorld::Ptr right) + { + if (left.getTypeName() == right.getTypeName()) + { + int cmp = MWWorld::Class::get(left).getName(left).compare( + MWWorld::Class::get(right).getName(right)); + return cmp < 0; + } + else + { + return compareType(left.getTypeName(), right.getTypeName()); + } + } +} + + +ContainerBase::ContainerBase(DragAndDrop* dragAndDrop) : + mDragAndDrop(dragAndDrop), + mFilter(ContainerBase::Filter_All) +{ +} + +void ContainerBase::setWidgets(Widget* containerWidget, ScrollView* itemView) +{ + mContainerWidget = containerWidget; + mItemView = itemView; + + mContainerWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onContainerClicked); + mContainerWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerWindow::onMouseWheel); +} + +ContainerBase::~ContainerBase() +{ +} + +void ContainerBase::onSelectedItem(MyGUI::Widget* _sender) +{ + mSelectedItem = _sender; + + if (mDragAndDrop && !isTrading()) + { + if(!mDragAndDrop->mIsOnDragAndDrop) + { + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + startDragItem(_sender, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + startDragItem(_sender, 1); + } + else + { + std::string message = MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTake")->str; + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::startDragItem); + } + } + else + onContainerClicked(mContainerWidget); + } + else + { + MWWorld::Ptr object = (*_sender->getUserData()); + int count = object.getRefData().getCount(); + + if (isInventory()) + { + // the player is trying to sell an item, check if the merchant accepts it + // also, don't allow selling gold (let's be better than Morrowind at this, can we?) + if (!MWBase::Environment::get().getWindowManager()->getTradeWindow()->npcAcceptsItem(object) + || MWWorld::Class::get(object).getName(object) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + // user notification "i don't buy this item" + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog4")->str, std::vector()); + return; + } + } + + bool buying = isTradeWindow(); // buying or selling? + std::string message = buying ? MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sQuanityMenuMessage02")->str + : MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sQuanityMenuMessage01")->str; + + if (std::find(mBoughtItems.begin(), mBoughtItems.end(), object) != mBoughtItems.end()) + { + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + sellAlreadyBoughtItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellAlreadyBoughtItem(NULL, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellAlreadyBoughtItem); + } + } + else + { + if (MyGUI::InputManager::getInstance().isShiftPressed() || count == 1) + { + sellItem(NULL, count); + } + else if (MyGUI::InputManager::getInstance().isControlPressed()) + { + sellItem(NULL, 1); + } + else + { + CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog(); + dialog->open(MWWorld::Class::get(object).getName(object), message, count); + dialog->eventOkClicked.clear(); + dialog->eventOkClicked += MyGUI::newDelegate(this, &ContainerBase::sellItem); + } + } + } +} + +void ContainerBase::sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count) +{ + MWWorld::Ptr object = *mSelectedItem->getUserData(); + + if (isInventory()) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + drawItems(); +} + +void ContainerBase::sellItem(MyGUI::Widget* _sender, int count) +{ + MWWorld::Ptr object = *mSelectedItem->getUserData(); + + if (isInventory()) + { + MWBase::Environment::get().getWindowManager()->getTradeWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->buyFromNpc(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->drawItems(); + } + else + { + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->addBarteredItem(object, count); + MWBase::Environment::get().getWindowManager()->getTradeWindow()->sellToNpc(object, count); + MWBase::Environment::get().getWindowManager()->getInventoryWindow()->drawItems(); + } + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + drawItems(); +} + +void ContainerBase::startDragItem(MyGUI::Widget* _sender, int count) +{ + mDragAndDrop->mIsOnDragAndDrop = true; + mSelectedItem->detachFromWidget(); + mSelectedItem->attachToWidget(mDragAndDrop->mDragAndDropWidget); + + MWWorld::Ptr object = *mSelectedItem->getUserData(); + _unequipItem(object); + + mDragAndDrop->mDraggedCount = count; + + mDragAndDrop->mDraggedFrom = this; + + std::string sound = MWWorld::Class::get(object).getUpSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + mDragAndDrop->mDraggedWidget = mSelectedItem; + static_cast(mSelectedItem)->setImageTexture(""); // remove the background texture (not visible during drag) + static_cast(mSelectedItem->getChildAt(0)->getChildAt(0))->setCaption( + getCountString(mDragAndDrop->mDraggedCount)); + + drawItems(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(true); +} + +void ContainerBase::onContainerClicked(MyGUI::Widget* _sender) +{ + if (mDragAndDrop == NULL) return; + + if(mDragAndDrop->mIsOnDragAndDrop) //drop item here + { + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + if (mDragAndDrop->mDraggedFrom != this) + { + assert(object.getContainerStore() && "Item is not in a container!"); + + // check the container's Organic flag (if this is a container). container with Organic flag doesn't allow putting items inside + if (mContainer.getTypeName() == typeid(ESM::Container).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->flags & ESM::Container::Organic) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sContentsMessage2")->str, std::vector()); + return; + } + } + + int origCount = object.getRefData().getCount(); + + // check that we don't exceed the allowed weight (only for containers, not for inventory) + if (!isInventory()) + { + float capacity = MWWorld::Class::get(mContainer).getCapacity(mContainer); + + // try adding the item, and if weight is exceeded, just remove it again. + object.getRefData().setCount(mDragAndDrop->mDraggedCount); + MWWorld::ContainerStoreIterator it = containerStore.add(object); + + float curWeight = MWWorld::Class::get(mContainer).getEncumbrance(mContainer); + if (curWeight > capacity) + { + it->getRefData().setCount(0); + object.getRefData().setCount(origCount); + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sContentsMessage3")->str, std::vector()); + return; + } + else + { + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + } + std::cout << "container weight " << curWeight << "/" << capacity << std::endl; + } + else + { + object.getRefData().setCount (mDragAndDrop->mDraggedCount); + containerStore.add(object); + object.getRefData().setCount (origCount - mDragAndDrop->mDraggedCount); + } + } + + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + drawItems(); + mDragAndDrop->mDraggedFrom->drawItems(); + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + } +} + +void ContainerBase::onMouseWheel(MyGUI::Widget* _sender, int _rel) +{ + if (mItemView->getViewOffset().left + _rel*0.3 > 0) + mItemView->setViewOffset(MyGUI::IntPoint(0, 0)); + else + mItemView->setViewOffset(MyGUI::IntPoint(mItemView->getViewOffset().left + _rel*0.3, 0)); +} + +void ContainerBase::setFilter(ContainerBase::Filter filter) +{ + mFilter = filter; + drawItems(); +} + +void ContainerBase::openContainer(MWWorld::Ptr container) +{ + mContainer = container; + drawItems(); +} + +void ContainerBase::drawItems() +{ + while (mContainerWidget->getChildCount()) + { + MyGUI::Gui::getInstance().destroyWidget(mContainerWidget->getChildAt(0)); + } + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + int x = 0; + int y = 0; + int maxHeight = mItemView->getSize().height - 58; + + int index = 0; + + + bool onlyMagic = false; + int categories; + if (mFilter == Filter_All) + categories = MWWorld::ContainerStore::Type_All; + else if (mFilter == Filter_Weapon) + categories = MWWorld::ContainerStore::Type_Weapon; + else if (mFilter == Filter_Apparel) + categories = MWWorld::ContainerStore::Type_Clothing + MWWorld::ContainerStore::Type_Armor; + else if (mFilter == Filter_Magic) + { + categories = MWWorld::ContainerStore::Type_Clothing + MWWorld::ContainerStore::Type_Armor + + MWWorld::ContainerStore::Type_Weapon + MWWorld::ContainerStore::Type_Book + + MWWorld::ContainerStore::Type_Potion; + onlyMagic = true; + } + else if (mFilter == Filter_Misc) + { + categories = MWWorld::ContainerStore::Type_Miscellaneous + MWWorld::ContainerStore::Type_Book + + MWWorld::ContainerStore::Type_Ingredient + MWWorld::ContainerStore::Type_Repair + + MWWorld::ContainerStore::Type_Lockpick + MWWorld::ContainerStore::Type_Light + + MWWorld::ContainerStore::Type_Apparatus; + } + + /// \todo performance improvement: don't create/destroy all the widgets everytime the container window changes size, only reposition them + + std::vector< std::pair > items; + + std::vector equippedItems = getEquippedItems(); + + // add bought items (always at the beginning) + std::vector boughtItems; + for (MWWorld::ContainerStoreIterator it (mBoughtItems.begin()); it!=mBoughtItems.end(); ++it) + { + boughtItems.push_back(*it); + } + std::sort(boughtItems.begin(), boughtItems.end(), sortItems); + + for (std::vector::iterator it=boughtItems.begin(); + it != boughtItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Barter) ); + } + + // filter out the equipped items of categories we don't want + std::vector unwantedItems = equippedItems; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + std::vector::iterator found = std::find(unwantedItems.begin(), unwantedItems.end(), *iter); + if (found != unwantedItems.end()) + { + unwantedItems.erase(found); + } + } + // now erase everything that's still in unwantedItems. + for (std::vector::iterator it=unwantedItems.begin(); + it != unwantedItems.end(); ++it) + { + std::vector::iterator found = std::find(equippedItems.begin(), equippedItems.end(), *it); + assert(found != equippedItems.end()); + equippedItems.erase(found); + } + // and add the items that are left (= have the correct category) + if (!ignoreEquippedItems()) + { + for (std::vector::const_iterator it=equippedItems.begin(); + it != equippedItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Equipped) ); + } + } + + std::vector ignoreItems = itemsToIgnore(); + + // now add the regular items + std::vector regularItems; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin(categories)); iter!=containerStore.end(); ++iter) + { + if (std::find(equippedItems.begin(), equippedItems.end(), *iter) == equippedItems.end() + && std::find(ignoreItems.begin(), ignoreItems.end(), *iter) == ignoreItems.end() + && std::find(mBoughtItems.begin(), mBoughtItems.end(), *iter) == mBoughtItems.end()) + regularItems.push_back(*iter); + } + + // sort them and add + std::sort(regularItems.begin(), regularItems.end(), sortItems); + for (std::vector::const_iterator it=regularItems.begin(); it!=regularItems.end(); ++it) + { + items.push_back( std::make_pair(*it, ItemState_Normal) ); + } + + for (std::vector< std::pair >::const_iterator it=items.begin(); + it != items.end(); ++it) + { + index++; + const MWWorld::Ptr* iter = &((*it).first); + + int displayCount = iter->getRefData().getCount(); + if (mDragAndDrop != NULL && mDragAndDrop->mIsOnDragAndDrop && *iter == *mDragAndDrop->mDraggedWidget->getUserData()) + { + displayCount -= mDragAndDrop->mDraggedCount; + } + if(displayCount > 0 && !(onlyMagic && it->second != ItemState_Barter && MWWorld::Class::get(*iter).getEnchantment(*iter) == "" && iter->getTypeName() != typeid(ESM::Potion).name())) + { + std::string path = std::string("icons\\"); + path+=MWWorld::Class::get(*iter).getInventoryIcon(*iter); + + // background widget (for the "equipped" frame and magic item background image) + bool isMagic = (MWWorld::Class::get(*iter).getEnchantment(*iter) != ""); + MyGUI::ImageBox* backgroundWidget = mContainerWidget->createWidget("ImageBox", MyGUI::IntCoord(x, y, 42, 42), MyGUI::Align::Default); + backgroundWidget->setUserString("ToolTipType", "ItemPtr"); + backgroundWidget->setUserData(*iter); + + std::string backgroundTex = "textures\\menu_icon"; + if (isMagic) + backgroundTex += "_magic"; + if (it->second == ItemState_Normal) + { + if (!isMagic) + backgroundTex = ""; + } + else if (it->second == ItemState_Equipped) + { + backgroundTex += "_equip"; + } + else if (it->second == ItemState_Barter) + { + backgroundTex += "_barter"; + } + if (backgroundTex != "") + backgroundTex += ".dds"; + + backgroundWidget->setImageTexture(backgroundTex); + if (it->second == ItemState_Barter && !isMagic) + backgroundWidget->setProperty("ImageCoord", "2 2 42 42"); + else + backgroundWidget->setProperty("ImageCoord", "0 0 42 42"); + backgroundWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerBase::onSelectedItem); + backgroundWidget->eventMouseWheel += MyGUI::newDelegate(this, &ContainerBase::onMouseWheel); + + // image + ImageBox* image = backgroundWidget->createWidget("ImageBox", MyGUI::IntCoord(5, 5, 32, 32), MyGUI::Align::Default); + int pos = path.rfind("."); + path.erase(pos); + path.append(".dds"); + image->setImageTexture(path); + image->setNeedMouseFocus(false); + + // text widget that shows item count + MyGUI::TextBox* text = image->createWidget("SandBrightText", MyGUI::IntCoord(0, 14, 32, 18), MyGUI::Align::Default, std::string("Label")); + text->setTextAlign(MyGUI::Align::Right); + text->setNeedMouseFocus(false); + text->setTextShadow(true); + text->setTextShadowColour(MyGUI::Colour(0,0,0)); + + y += 42; + if (y > maxHeight) + { + x += 42; + y = 0; + } + + text->setCaption(getCountString(displayCount)); + } + } + + MyGUI::IntSize size = MyGUI::IntSize(std::max(mItemView->getSize().width, x+42), mItemView->getSize().height); + mItemView->setCanvasSize(size); + mContainerWidget->setSize(size); +} + +std::string ContainerBase::getCountString(const int count) +{ + if (count == 1) + return ""; + if (count > 9999) + return boost::lexical_cast(int(count/1000.f)) + "k"; + else + return boost::lexical_cast(count); +} + +void ContainerBase::addBarteredItem(MWWorld::Ptr item, int count) +{ + int origCount = item.getRefData().getCount(); + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = mBoughtItems.add(item); + item.getRefData().setCount(origCount - count); +} + +void ContainerBase::addItem(MWWorld::Ptr item, int count) +{ + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + int origCount = item.getRefData().getCount(); + + item.getRefData().setCount(count); + MWWorld::ContainerStoreIterator it = containerStore.add(item); + + item.getRefData().setCount(origCount - count); +} + +void ContainerBase::transferBoughtItems() +{ + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + containerStore.add(*it); + } +} + +void ContainerBase::returnBoughtItems(MWWorld::ContainerStore& store) +{ + for (MWWorld::ContainerStoreIterator it(mBoughtItems.begin()); it != mBoughtItems.end(); ++it) + { + store.add(*it); + } +} + +MWWorld::ContainerStore& ContainerBase::getContainerStore() +{ + MWWorld::ContainerStore& store = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + return store; +} + +// ------------------------------------------------------------------------------------------------ + +ContainerWindow::ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + : ContainerBase(dragAndDrop) + , WindowBase("openmw_container_window_layout.xml", parWindowManager) +{ + getWidget(mTakeButton, "TakeButton"); + getWidget(mCloseButton, "CloseButton"); + + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + mCloseButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onCloseButtonClicked); + mTakeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ContainerWindow::onTakeAllButtonClicked); + + // adjust buttons size to fit text + int closeButtonWidth = mCloseButton->getTextSize().width+24; + int takeButtonWidth = mTakeButton->getTextSize().width+24; + mCloseButton->setCoord(600-20-closeButtonWidth, mCloseButton->getCoord().top, closeButtonWidth, mCloseButton->getCoord().height); + mTakeButton->setCoord(600-20-closeButtonWidth-takeButtonWidth-8, mTakeButton->getCoord().top, takeButtonWidth, mTakeButton->getCoord().height); + + int w = MyGUI::RenderManager::getInstance().getViewSize().width; + //int h = MyGUI::RenderManager::getInstance().getViewSize().height; + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &ContainerWindow::onWindowResize); + + setCoord(w-600,0,600,300); +} + +ContainerWindow::~ContainerWindow() +{ +} + +void ContainerWindow::onWindowResize(MyGUI::Window* window) +{ + drawItems(); +} + +void ContainerWindow::open(MWWorld::Ptr container) +{ + openContainer(container); + setTitle(MWWorld::Class::get(container).getName(container)); +} + +void ContainerWindow::onCloseButtonClicked(MyGUI::Widget* _sender) +{ + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + } +} + +void ContainerWindow::onTakeAllButtonClicked(MyGUI::Widget* _sender) +{ + if(mDragAndDrop == NULL || !mDragAndDrop->mIsOnDragAndDrop) + { + // transfer everything into the player's inventory + MWWorld::ContainerStore& containerStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::ContainerStore& playerStore = MWWorld::Class::get(player).getContainerStore(player); + + int i=0; + for (MWWorld::ContainerStoreIterator iter (containerStore.begin()); iter!=containerStore.end(); ++iter) + { + playerStore.add(*iter); + + if (i==0) + { + // play the sound of the first object + std::string sound = MWWorld::Class::get(*iter).getUpSoundId(*iter); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + } + + ++i; + } + + containerStore.clear(); + + MWBase::Environment::get().getWindowManager()->setGuiMode(GM_Game); + } +} diff --git a/apps/openmw/mwgui/container.hpp b/apps/openmw/mwgui/container.hpp new file mode 100644 index 0000000000..66cac82ce6 --- /dev/null +++ b/apps/openmw/mwgui/container.hpp @@ -0,0 +1,141 @@ +#ifndef MGUI_CONTAINER_H +#define MGUI_CONTAINER_H + +#include +#include "../mwclass/container.hpp" +#include +#include +#include +#include +#include "window_base.hpp" +#include "../mwworld/ptr.hpp" +#include "../mwworld/containerstore.hpp" +#include + +namespace MWWorld +{ + class Environment; +} + +namespace MyGUI +{ + class Gui; + class Widget; +} + +namespace MWGui +{ + class WindowManager; + class ContainerWindow; + class ContainerBase; +} + + +namespace MWGui +{ + class DragAndDrop + { + public: + bool mIsOnDragAndDrop; + MyGUI::Widget* mDraggedWidget; + MyGUI::Widget* mDragAndDropWidget; + ContainerBase* mDraggedFrom; + int mDraggedCount; + }; + + class ContainerBase + { + public: + ContainerBase(DragAndDrop* dragAndDrop); + virtual ~ContainerBase(); + + enum Filter + { + Filter_All = 0x01, + Filter_Weapon = 0x02, + Filter_Apparel = 0x03, + Filter_Magic = 0x04, + Filter_Misc = 0x05 + }; + + enum ItemState + { + ItemState_Normal = 0x01, + ItemState_Equipped = 0x02, + ItemState_Barter = 0x03 + }; + + void setWidgets(MyGUI::Widget* containerWidget, MyGUI::ScrollView* itemView); ///< only call once + + void addBarteredItem(MWWorld::Ptr item, int count); + void addItem(MWWorld::Ptr item, int count); + + void transferBoughtItems(); ///< transfer bought items into the inventory + void returnBoughtItems(MWWorld::ContainerStore& store); ///< return bought items into the specified ContainerStore + + MWWorld::ContainerStore& getContainerStore(); + MWWorld::ContainerStore& getBoughtItems() { return mBoughtItems; } + + void openContainer(MWWorld::Ptr container); + void setFilter(Filter filter); ///< set category filter + void drawItems(); + + protected: + MyGUI::ScrollView* mItemView; + MyGUI::Widget* mContainerWidget; + + MyGUI::Widget* mSelectedItem; + + DragAndDrop* mDragAndDrop; + MWWorld::Ptr mContainer; + + Filter mFilter; + + // bought items are put in a separate ContainerStore so that they don't stack with other (not bought) items. + MWWorld::ContainerStore mBoughtItems; + + void onSelectedItem(MyGUI::Widget* _sender); + void onContainerClicked(MyGUI::Widget* _sender); + void onMouseWheel(MyGUI::Widget* _sender, int _rel); + + /// start dragging an item (drag & drop) + void startDragItem(MyGUI::Widget* _sender, int count); + + /// sell an item from this container + void sellItem(MyGUI::Widget* _sender, int count); + + /// sell an item from this container, that was previously just bought + void sellAlreadyBoughtItem(MyGUI::Widget* _sender, int count); + + std::string getCountString(const int count); + + virtual bool isTradeWindow() { return false; } + virtual bool isInventory() { return false; } + virtual std::vector getEquippedItems() { return std::vector(); } + virtual void _unequipItem(MWWorld::Ptr item) { ; } + + virtual bool isTrading() { return false; } + + virtual bool ignoreEquippedItems() { return false; } + virtual std::vector itemsToIgnore() { return std::vector(); } + }; + + class ContainerWindow : public ContainerBase, public WindowBase + { + public: + ContainerWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + + virtual ~ContainerWindow(); + + void open(MWWorld::Ptr container); + + protected: + MyGUI::Button* mTakeButton; + MyGUI::Button* mCloseButton; + + void onWindowResize(MyGUI::Window* window); + void onCloseButtonClicked(MyGUI::Widget* _sender); + void onTakeAllButtonClicked(MyGUI::Widget* _sender); + }; +} +#endif // CONTAINER_H diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp new file mode 100644 index 0000000000..16e3f9aab3 --- /dev/null +++ b/apps/openmw/mwgui/countdialog.cpp @@ -0,0 +1,111 @@ +#include "countdialog.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + +namespace MWGui +{ + CountDialog::CountDialog(WindowManager& parWindowManager) : + WindowBase("openmw_count_window_layout.xml", parWindowManager) + { + getWidget(mSlider, "CountSlider"); + getWidget(mItemEdit, "ItemEdit"); + getWidget(mItemText, "ItemText"); + getWidget(mLabelText, "LabelText"); + getWidget(mOkButton, "OkButton"); + getWidget(mCancelButton, "CancelButton"); + + mOkButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sOk")->str); + mCancelButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sCancel")->str); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onCancelButtonClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CountDialog::onOkButtonClicked); + mItemEdit->eventEditTextChange += MyGUI::newDelegate(this, &CountDialog::onEditTextChange); + mSlider->eventScrollChangePosition += MyGUI::newDelegate(this, &CountDialog::onSliderMoved); + } + + void CountDialog::open(const std::string& item, const std::string& message, const int maxCount) + { + setVisible(true); + + mLabelText->setCaption(message); + + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + + mSlider->setScrollRange(maxCount); + mItemText->setCaption(item); + + int width = std::max(mItemText->getTextSize().width + 128, 320); + setCoord(viewSize.width/2 - width/2, + viewSize.height/2 - mMainWidget->getHeight()/2, + width, + mMainWidget->getHeight()); + + // make other gui elements inaccessible while this dialog is open + MyGUI::InputManager::getInstance().addWidgetModal(mMainWidget); + + MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit); + + mSlider->setScrollPosition(maxCount-1); + mItemEdit->setCaption(boost::lexical_cast(maxCount)); + + int okButtonWidth = mOkButton->getTextSize().width + 24; + mOkButton->setCoord(width - 30 - okButtonWidth, + mOkButton->getTop(), + okButtonWidth, + mOkButton->getHeight()); + + int cancelButtonWidth = mCancelButton->getTextSize().width + 24; + mCancelButton->setCoord(width - 30 - okButtonWidth - cancelButtonWidth - 8, + mCancelButton->getTop(), + cancelButtonWidth, + mCancelButton->getHeight()); + } + + void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) + { + close(); + } + + void CountDialog::onOkButtonClicked(MyGUI::Widget* _sender) + { + eventOkClicked(NULL, mSlider->getScrollPosition()+1); + + close(); + } + + void CountDialog::onEditTextChange(MyGUI::EditBox* _sender) + { + if (_sender->getCaption() == "") + return; + + unsigned int count; + try + { + count = boost::lexical_cast(_sender->getCaption()); + } + catch (std::bad_cast&) + { + count = 1; + } + if (count > mSlider->getScrollRange()) + { + count = mSlider->getScrollRange(); + } + mSlider->setScrollPosition(count-1); + onSliderMoved(mSlider, count-1); + } + + void CountDialog::onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position) + { + mItemEdit->setCaption(boost::lexical_cast(_position+1)); + } + + void CountDialog::close() + { + setVisible(false); + MyGUI::InputManager::getInstance().removeWidgetModal(mMainWidget); + } +} diff --git a/apps/openmw/mwgui/countdialog.hpp b/apps/openmw/mwgui/countdialog.hpp new file mode 100644 index 0000000000..aac17b846d --- /dev/null +++ b/apps/openmw/mwgui/countdialog.hpp @@ -0,0 +1,39 @@ +#ifndef MWGUI_COUNTDIALOG_H +#define MWGUI_COUNTDIALOG_H + +#include "window_base.hpp" + +namespace MWGui +{ + class CountDialog : public WindowBase + { + public: + CountDialog(WindowManager& parWindowManager); + void open(const std::string& item, const std::string& message, const int maxCount); + + typedef MyGUI::delegates::CMultiDelegate2 EventHandle_WidgetInt; + + /** Event : Ok button was clicked.\n + signature : void method(MyGUI::Widget* _sender, int _count)\n + */ + EventHandle_WidgetInt eventOkClicked; + + private: + MyGUI::ScrollBar* mSlider; + MyGUI::EditBox* mItemEdit; + MyGUI::TextBox* mItemText; + MyGUI::TextBox* mLabelText; + MyGUI::Button* mOkButton; + MyGUI::Button* mCancelButton; + + void onCancelButtonClicked(MyGUI::Widget* _sender); + void onOkButtonClicked(MyGUI::Widget* _sender); + void onEditTextChange(MyGUI::EditBox* _sender); + void onSliderMoved(MyGUI::ScrollBar* _sender, size_t _position); + + void close(); + }; + +} + +#endif diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 45163017a6..53ab98aeb0 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -1,11 +1,4 @@ #include "dialogue.hpp" -#include "dialogue_history.hpp" -#include "window_manager.hpp" -#include "widgets.hpp" -#include "list.hpp" -#include "components/esm_store/store.hpp" -#include "../mwbase/environment.hpp" -#include "../mwdialogue/dialoguemanager.hpp" #include #include @@ -14,6 +7,18 @@ #include #include +#include + +#include "../mwbase/environment.hpp" +#include "../mwdialogue/dialoguemanager.hpp" + +#include "dialogue_history.hpp" +#include "window_manager.hpp" +#include "widgets.hpp" +#include "list.hpp" +#include "tradewindow.hpp" +#include "inventorywindow.hpp" + using namespace MWGui; using namespace Widgets; @@ -40,6 +45,7 @@ std::string::size_type find_str_ci(const std::string& str, const std::string& su DialogueWindow::DialogueWindow(WindowManager& parWindowManager) : WindowBase("openmw_dialogue_window_layout.xml", parWindowManager) , mEnabled(true) + , mShowTrade(false) { // Centre dialog center(); @@ -58,14 +64,11 @@ DialogueWindow::DialogueWindow(WindowManager& parWindowManager) //Topics list getWidget(topicsList, "TopicsList"); - //topicsList->eventListSelectAccept += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); topicsList->eventItemSelected += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); - //topicsList->eventListChangePosition += MyGUI::newDelegate(this, &DialogueWindow::onSelectTopic); MyGUI::ButtonPtr byeButton; getWidget(byeButton, "ByeButton"); byeButton->eventMouseButtonClick += MyGUI::newDelegate(this, &DialogueWindow::onByeClicked); - byeButton->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGoodbye")->str); getWidget(pDispositionBar, "Disposition"); getWidget(pDispositionText,"DispositionText"); @@ -127,24 +130,42 @@ void DialogueWindow::onSelectTopic(std::string topic) { if (!mEnabled) return; - MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); + if (topic == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str) + { + /// \todo check if the player is allowed to trade with this actor (e.g. faction rank high enough)? + mWindowManager.setGuiMode(GM_Barter); + mWindowManager.getTradeWindow()->startTrade(mActor); + } + + else + MWBase::Environment::get().getDialogueManager()->keywordSelected(lower_string(topic)); } -void DialogueWindow::startDialogue(std::string npcName) +void DialogueWindow::startDialogue(MWWorld::Ptr actor, std::string npcName) { mEnabled = true; + mActor = actor; topicsList->setEnabled(true); - static_cast(mMainWidget)->setCaption(npcName); - adjustWindowCaption(); + setTitle(npcName); } void DialogueWindow::setKeywords(std::list keyWords) { topicsList->clear(); + + bool anyService = mShowTrade; + + if (mShowTrade) + topicsList->addItem(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarter")->str); + + if (anyService) + topicsList->addSeparator(); + for(std::list::iterator it = keyWords.begin(); it != keyWords.end(); it++) { topicsList->addItem(*it); } + topicsList->adjustSize(); } void DialogueWindow::removeKeyword(std::string keyWord) @@ -154,6 +175,7 @@ void DialogueWindow::removeKeyword(std::string keyWord) topicsList->removeItem(keyWord); pTopicsText.erase(keyWord); } + topicsList->adjustSize(); } void addColorInString(std::string& str, const std::string& keyword,std::string color1, std::string color2) @@ -192,7 +214,8 @@ std::string DialogueWindow::parseText(std::string text) for(unsigned int i = 0;igetItemCount();i++) { std::string keyWord = topicsList->getItemNameAt(i); - addColorInString(text,keyWord,"#686EBA","#B29154"); + if (keyWord != "") + addColorInString(text,keyWord,"#686EBA","#B29154"); } return text; } diff --git a/apps/openmw/mwgui/dialogue.hpp b/apps/openmw/mwgui/dialogue.hpp index a29e737997..7f69f972c7 100644 --- a/apps/openmw/mwgui/dialogue.hpp +++ b/apps/openmw/mwgui/dialogue.hpp @@ -4,6 +4,8 @@ #include "window_base.hpp" #include +#include "../mwworld/ptr.hpp" + namespace MWGui { class WindowManager; @@ -38,7 +40,7 @@ namespace MWGui */ EventHandle_Void eventBye; - void startDialogue(std::string npcName); + void startDialogue(MWWorld::Ptr actor, std::string npcName); void stopDialogue(); void setKeywords(std::list keyWord); void removeKeyword(std::string keyWord); @@ -47,6 +49,10 @@ namespace MWGui void askQuestion(std::string question); void goodbye(); + // various service button visibilities, depending if the npc/creature talked to has these services + // make sure to call these before setKeywords() + void setShowTrade(bool show) { mShowTrade = show; } + protected: void onSelectTopic(std::string topic); void onByeClicked(MyGUI::Widget* _sender); @@ -61,8 +67,13 @@ namespace MWGui */ std::string parseText(std::string text); + // various service button visibilities, depending if the npc/creature talked to has these services + bool mShowTrade; + bool mEnabled; + MWWorld::Ptr mActor; // actor being talked to + DialogueHistory* history; Widgets::MWList* topicsList; MyGUI::ProgressPtr pDispositionBar; diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/hud.cpp similarity index 61% rename from apps/openmw/mwgui/layouts.cpp rename to apps/openmw/mwgui/hud.cpp index 21302d7c1d..892bd6c7aa 100644 --- a/apps/openmw/mwgui/layouts.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,19 +1,23 @@ -#include "layouts.hpp" - -#include "../mwmechanics/mechanicsmanager.hpp" -#include "window_manager.hpp" +#include "hud.hpp" #include -#include -#include -#undef min -#undef max +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwsound/soundmanager.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" + +#include "window_manager.hpp" +#include "container.hpp" using namespace MWGui; - -HUD::HUD(int width, int height, int fpsLevel) +HUD::HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop) : Layout("openmw_hud_layout.xml") , health(NULL) , magicka(NULL) @@ -36,6 +40,7 @@ HUD::HUD(int width, int height, int fpsLevel) , spellBoxBaseLeft(0) , effectBoxBaseRight(0) , minimapBoxBaseRight(0) + , mDragAndDrop(dragAndDrop) { setCoord(0,0, width, height); @@ -72,9 +77,6 @@ HUD::HUD(int width, int height, int fpsLevel) getWidget(trianglecounter, "TriangleCounter"); getWidget(batchcounter, "BatchCounter"); - compass->setImageTexture("textures\\compass.dds"); - crosshair->setImageTexture("textures\\target.dds"); - // These are just demo values, you should replace these with // real calls from outside the class later. setWeapIcon("icons\\w\\tx_knife_iron.dds"); @@ -84,6 +86,10 @@ HUD::HUD(int width, int height, int fpsLevel) setEffect("icons\\s\\tx_s_chameleon.dds"); LocalMapBase::init(minimap, this); + + mMainWidget->eventMouseButtonClick += MyGUI::newDelegate(this, &HUD::onWorldClicked); + mMainWidget->eventMouseMove += MyGUI::newDelegate(this, &HUD::onWorldMouseOver); + mMainWidget->eventMouseLostFocus += MyGUI::newDelegate(this, &HUD::onWorldMouseLostFocus); } void HUD::setFpsLevel(int level) @@ -123,16 +129,6 @@ void HUD::setBatchCount(size_t count) batchcounter->setCaption(boost::lexical_cast(count)); } -void HUD::setStats(int h, int hmax, int m, int mmax, int s, int smax) -{ - health->setProgressRange(hmax); - health->setProgressPosition(h); - magicka->setProgressRange(mmax); - magicka->setProgressPosition(m); - stamina->setProgressRange(smax); - stamina->setProgressPosition(s); -} - void HUD::setWeapIcon(const char *str) { weapImage->setImageTexture(str); @@ -170,19 +166,27 @@ void HUD::setValue(const std::string& id, const MWMechanics::DynamicStat& v for (int i=0; ids[i]; ++i) if (ids[i]==id) { + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); switch (i) { case 0: health->setProgressRange (value.getModified()); health->setProgressPosition (value.getCurrent()); + getWidget(w, "HealthFrame"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); break; case 1: magicka->setProgressRange (value.getModified()); magicka->setProgressPosition (value.getCurrent()); + getWidget(w, "MagickaFrame"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); break; case 2: stamina->setProgressRange (value.getModified()); stamina->setProgressPosition (value.getCurrent()); + getWidget(w, "FatigueFrame"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); break; } } @@ -247,86 +251,72 @@ void HUD::setBottomRightVisibility(bool effectBoxVisible, bool minimapBoxVisible effectBox->setVisible(effectBoxVisible); } -LocalMapBase::LocalMapBase() - : mCurX(0) - , mCurY(0) - , mInterior(false) - , mFogOfWar(true) - , mLocalMap(NULL) - , mPrefix() - , mChanged(true) - , mLayout(NULL) - , mLastPositionX(0.0f) - , mLastPositionY(0.0f) - , mLastDirectionX(0.0f) - , mLastDirectionY(0.0f) +void HUD::onWorldClicked(MyGUI::Widget* _sender) { -} - -void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout) -{ - mLocalMap = widget; - mLayout = layout; -} - -void LocalMapBase::setCellPrefix(const std::string& prefix) -{ - mPrefix = prefix; - mChanged = true; -} - -void LocalMapBase::toggleFogOfWar() -{ - mFogOfWar = !mFogOfWar; - applyFogOfWar(); -} - -void LocalMapBase::applyFogOfWar() -{ - for (int mx=0; mx<3; ++mx) + if (mDragAndDrop->mIsOnDragAndDrop) { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); - std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" - + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); - MyGUI::ImageBox* fog; - mLayout->getWidget(fog, name+"_fog"); - fog->setImageTexture(mFogOfWar ? - ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" - : "black.png" ) - : ""); - } + // drop item into the gameworld + MWWorld::Ptr object = *mDragAndDrop->mDraggedWidget->getUserData(); + + MWWorld::World* world = MWBase::Environment::get().getWorld(); + + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); + + int origCount = object.getRefData().getCount(); + object.getRefData().setCount(mDragAndDrop->mDraggedCount); + + if (world->canPlaceObject(mouseX, mouseY)) + world->placeObject(object, mouseX, mouseY); + else + world->dropObjectOnGround(object); + + MyGUI::PointerManager::getInstance().setPointer("arrow"); + + std::string sound = MWWorld::Class::get(object).getDownSoundId(object); + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + // remove object from the container it was coming from + object.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget = 0; + + MWBase::Environment::get().getWindowManager()->setDragDrop(false); } } -void LocalMapBase::setActiveCell(const int x, const int y, bool interior) +void HUD::onWorldMouseOver(MyGUI::Widget* _sender, int x, int y) { - if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell - for (int mx=0; mx<3; ++mx) + if (mDragAndDrop->mIsOnDragAndDrop) { - for (int my=0; my<3; ++my) - { - std::string name = "Map_" + boost::lexical_cast(mx) + "_" - + boost::lexical_cast(my); + MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); + MyGUI::IntPoint cursorPosition = MyGUI::InputManager::getInstance().getMousePosition(); + float mouseX = cursorPosition.left / float(viewSize.width); + float mouseY = cursorPosition.top / float(viewSize.height); - std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" - + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); + MWWorld::World* world = MWBase::Environment::get().getWorld(); - MyGUI::ImageBox* box; - mLayout->getWidget(box, name); + // if we can't drop the object at the wanted position, show the "drop on ground" cursor. + bool canDrop = world->canPlaceObject(mouseX, mouseY); + + if (!canDrop) + MyGUI::PointerManager::getInstance().setPointer("drop_ground"); + else + MyGUI::PointerManager::getInstance().setPointer("arrow"); - if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) - box->setImageTexture(image); - else - box->setImageTexture("black.png"); - } } - mInterior = interior; - mCurX = x; - mCurY = y; - mChanged = false; - applyFogOfWar(); + else + { + MyGUI::PointerManager::getInstance().setPointer("arrow"); + /// \todo make it possible to pick up objects with the mouse, if inventory or container window is open + } } +void HUD::onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new) +{ + MyGUI::PointerManager::getInstance().setPointer("arrow"); +} diff --git a/apps/openmw/mwgui/hud.hpp b/apps/openmw/mwgui/hud.hpp new file mode 100644 index 0000000000..81f64ee504 --- /dev/null +++ b/apps/openmw/mwgui/hud.hpp @@ -0,0 +1,57 @@ +#include "map_window.hpp" + +#include + +#include "../mwmechanics/stat.hpp" + +namespace MWGui +{ + class DragAndDrop; + + class HUD : public OEngine::GUI::Layout, public LocalMapBase + { + public: + HUD(int width, int height, int fpsLevel, DragAndDrop* dragAndDrop); + void setWeapIcon(const char *str); + void setSpellIcon(const char *str); + void setWeapStatus(int s, int smax); + void setSpellStatus(int s, int smax); + void setEffect(const char *img); + void setValue (const std::string& id, const MWMechanics::DynamicStat& value); + void setFPS(float fps); + void setTriangleCount(size_t count); + void setBatchCount(size_t count); + void setPlayerDir(const float x, const float y); + void setPlayerPos(const float x, const float y); + void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); + void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); + void setFpsLevel(const int level); + + MyGUI::ProgressPtr health, magicka, stamina; + MyGUI::Widget *weapBox, *spellBox; + MyGUI::ImageBox *weapImage, *spellImage; + MyGUI::ProgressPtr weapStatus, spellStatus; + MyGUI::Widget *effectBox, *minimapBox; + MyGUI::ImageBox* effect1; + MyGUI::ScrollView* minimap; + MyGUI::ImageBox* compass; + MyGUI::ImageBox* crosshair; + + MyGUI::WidgetPtr fpsbox; + MyGUI::TextBox* fpscounter; + MyGUI::TextBox* trianglecounter; + MyGUI::TextBox* batchcounter; + + private: + // bottom left elements + int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; + // bottom right elements + int minimapBoxBaseRight, effectBoxBaseRight; + + DragAndDrop* mDragAndDrop; + + void onWorldClicked(MyGUI::Widget* _sender); + void onWorldMouseOver(MyGUI::Widget* _sender, int x, int y); + void onWorldMouseLostFocus(MyGUI::Widget* _sender, MyGUI::Widget* _new); + }; +} diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp new file mode 100644 index 0000000000..59be6a4959 --- /dev/null +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -0,0 +1,262 @@ +#include "inventorywindow.hpp" + +#include +#include +#include +#include +#include + +#include + +#include "../mwclass/container.hpp" +#include "../mwworld/containerstore.hpp" +#include "../mwworld/class.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" +#include "../mwbase/environment.hpp" +#include "../mwworld/manualref.hpp" + +#include "window_manager.hpp" +#include "widgets.hpp" +#include "bookwindow.hpp" +#include "scrollwindow.hpp" + +namespace +{ + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } +} + +namespace MWGui +{ + + InventoryWindow::InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop) + : ContainerBase(dragAndDrop) + , WindowPinnableBase("openmw_inventory_window_layout.xml", parWindowManager) + , mTrading(false) + { + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &InventoryWindow::onWindowResize); + + getWidget(mAvatar, "Avatar"); + getWidget(mEncumbranceBar, "EncumbranceBar"); + getWidget(mEncumbranceText, "EncumbranceBarT"); + getWidget(mFilterAll, "AllButton"); + getWidget(mFilterWeapon, "WeaponButton"); + getWidget(mFilterApparel, "ApparelButton"); + getWidget(mFilterMagic, "MagicButton"); + getWidget(mFilterMisc, "MiscButton"); + getWidget(mLeftPane, "LeftPane"); + getWidget(mRightPane, "RightPane"); + + mAvatar->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onAvatarClicked); + + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + // adjust size of buttons to fit text + int curX = 0; + mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); + curX += mFilterAll->getTextSize().width + 24 + 4; + + mFilterWeapon->setPosition(curX, mFilterWeapon->getPosition().top); + mFilterWeapon->setSize( mFilterWeapon->getTextSize().width + 24, mFilterWeapon->getSize().height ); + curX += mFilterWeapon->getTextSize().width + 24 + 4; + + mFilterApparel->setPosition(curX, mFilterApparel->getPosition().top); + mFilterApparel->setSize( mFilterApparel->getTextSize().width + 24, mFilterApparel->getSize().height ); + curX += mFilterApparel->getTextSize().width + 24 + 4; + + mFilterMagic->setPosition(curX, mFilterMagic->getPosition().top); + mFilterMagic->setSize( mFilterMagic->getTextSize().width + 24, mFilterMagic->getSize().height ); + curX += mFilterMagic->getTextSize().width + 24 + 4; + + mFilterMisc->setPosition(curX, mFilterMisc->getPosition().top); + mFilterMisc->setSize( mFilterMisc->getTextSize().width + 24, mFilterMisc->getSize().height ); + + mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onFilterChanged); + + mFilterAll->setStateSelected(true); + + setCoord(0, 342, 600, 258); + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + openContainer(player); + } + + void InventoryWindow::openInventory() + { + updateEncumbranceBar(); + + mTrading = false; + + mBoughtItems.clear(); + + onWindowResize(static_cast(mMainWidget)); + } + + void InventoryWindow::onWindowResize(MyGUI::Window* _sender) + { + const float aspect = 0.5; // fixed aspect ratio for the left pane + mLeftPane->setSize( (_sender->getSize().height-44) * aspect, _sender->getSize().height-44 ); + mRightPane->setCoord( mLeftPane->getPosition().left + (_sender->getSize().height-44) * aspect + 4, + mRightPane->getPosition().top, + _sender->getSize().width - 12 - (_sender->getSize().height-44) * aspect - 15, + _sender->getSize().height-44 ); + drawItems(); + } + + void InventoryWindow::onFilterChanged(MyGUI::Widget* _sender) + { + if (_sender == mFilterAll) + setFilter(ContainerBase::Filter_All); + else if (_sender == mFilterWeapon) + setFilter(ContainerBase::Filter_Weapon); + else if (_sender == mFilterApparel) + setFilter(ContainerBase::Filter_Apparel); + else if (_sender == mFilterMagic) + setFilter(ContainerBase::Filter_Magic); + else if (_sender == mFilterMisc) + setFilter(ContainerBase::Filter_Misc); + + mFilterAll->setStateSelected(false); + mFilterWeapon->setStateSelected(false); + mFilterApparel->setStateSelected(false); + mFilterMagic->setStateSelected(false); + mFilterMisc->setStateSelected(false); + + static_cast(_sender)->setStateSelected(true); + } + + void InventoryWindow::onPinToggled() + { + mWindowManager.setWeaponVisibility(!mPinned); + } + + void InventoryWindow::onAvatarClicked(MyGUI::Widget* _sender) + { + if (mDragAndDrop->mIsOnDragAndDrop) + { + MWWorld::Ptr ptr = *mDragAndDrop->mDraggedWidget->getUserData(); + + if (mDragAndDrop->mDraggedFrom != this) + { + // add item to the player's inventory + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + MWWorld::ContainerStoreIterator it = invStore.begin(); + + int origCount = ptr.getRefData().getCount(); + ptr.getRefData().setCount(origCount - mDragAndDrop->mDraggedCount); + it = invStore.add(ptr); + (*it).getRefData().setCount(mDragAndDrop->mDraggedCount); + ptr = *it; + } + + /// \todo scripts + + boost::shared_ptr action = MWWorld::Class::get(ptr).use(ptr); + + action->execute(); + + // this is necessary for books/scrolls: if they are already in the player's inventory, + // the "Take" button should not be visible. + // NOTE: the take button is "reset" when the window opens, so we can safely do the following + // without screwing up future book windows + if (mDragAndDrop->mDraggedFrom == this) + { + mWindowManager.getBookWindow()->setTakeButtonShow(false); + mWindowManager.getScrollWindow()->setTakeButtonShow(false); + } + + mDragAndDrop->mIsOnDragAndDrop = false; + MyGUI::Gui::getInstance().destroyWidget(mDragAndDrop->mDraggedWidget); + + mWindowManager.setDragDrop(false); + + drawItems(); + } + } + + std::vector InventoryWindow::getEquippedItems() + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + + std::vector items; + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; + } + + void InventoryWindow::_unequipItem(MWWorld::Ptr item) + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end() && *it == item) + { + invStore.equip(slot, invStore.end()); + return; + } + } + } + + void InventoryWindow::updateEncumbranceBar() + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + + float capacity = MWWorld::Class::get(player).getCapacity(player); + float encumbrance = MWWorld::Class::get(player).getEncumbrance(player); + mEncumbranceBar->setProgressRange(capacity); + mEncumbranceBar->setProgressPosition(encumbrance); + mEncumbranceText->setCaption( boost::lexical_cast(int(encumbrance)) + "/" + boost::lexical_cast(int(capacity)) ); + } + + void InventoryWindow::onFrame() + { + if (!mMainWidget->getVisible()) + return; + + updateEncumbranceBar(); + } + + int InventoryWindow::getPlayerGold() + { + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + + for (MWWorld::ContainerStoreIterator it = invStore.begin(); + it != invStore.end(); ++it) + { + if (toLower(it->getCellRef().refID) == "gold_001") + return it->getRefData().getCount(); + } + return 0; + } + + void InventoryWindow::startTrade() + { + mTrading = true; + } +} diff --git a/apps/openmw/mwgui/inventorywindow.hpp b/apps/openmw/mwgui/inventorywindow.hpp new file mode 100644 index 0000000000..fdb4438292 --- /dev/null +++ b/apps/openmw/mwgui/inventorywindow.hpp @@ -0,0 +1,54 @@ +#ifndef MGUI_Inventory_H +#define MGUI_Inventory_H + +#include "container.hpp" +#include "window_pinnable_base.hpp" + +namespace MWGui +{ + class InventoryWindow : public ContainerBase, public WindowPinnableBase + { + public: + InventoryWindow(WindowManager& parWindowManager,DragAndDrop* dragAndDrop); + + void openInventory(); + + /// start trading, disables item drag&drop + void startTrade(); + + void onFrame(); + + int getPlayerGold(); + + protected: + MyGUI::Widget* mAvatar; + MyGUI::TextBox* mArmorRating; + MyGUI::ProgressBar* mEncumbranceBar; + MyGUI::TextBox* mEncumbranceText; + + MyGUI::Widget* mLeftPane; + MyGUI::Widget* mRightPane; + + MyGUI::Button* mFilterAll; + MyGUI::Button* mFilterWeapon; + MyGUI::Button* mFilterApparel; + MyGUI::Button* mFilterMagic; + MyGUI::Button* mFilterMisc; + + bool mTrading; + + void onWindowResize(MyGUI::Window* _sender); + void onFilterChanged(MyGUI::Widget* _sender); + void onAvatarClicked(MyGUI::Widget* _sender); + void onPinToggled(); + + void updateEncumbranceBar(); + + virtual bool isTrading() { return mTrading; } + virtual bool isInventory() { return true; } + virtual std::vector getEquippedItems(); + virtual void _unequipItem(MWWorld::Ptr item); + }; +} + +#endif // Inventory_H diff --git a/apps/openmw/mwgui/layouts.hpp b/apps/openmw/mwgui/layouts.hpp deleted file mode 100644 index 19d96d2efa..0000000000 --- a/apps/openmw/mwgui/layouts.hpp +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef MWGUI_LAYOUTS_H -#define MWGUI_LAYOUTS_H - -#include - -#include -#include - -#include -#include -#include -#include - -#include "../mwmechanics/stat.hpp" -#include "window_base.hpp" - -#include - -/* - This file contains classes corresponding to window layouts - defined in resources/mygui/ *.xml. - - Each class inherites GUI::Layout and loads the XML file, and - provides some helper functions to manipulate the elements of the - window. - - The windows are never created or destroyed (except at startup and - shutdown), they are only hid. You can control visibility with - setVisible(). - */ - -namespace MWGui -{ - class LocalMapBase - { - public: - LocalMapBase(); - void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout); - - void setCellPrefix(const std::string& prefix); - void setActiveCell(const int x, const int y, bool interior=false); - - void toggleFogOfWar(); - - protected: - int mCurX, mCurY; - bool mInterior; - MyGUI::ScrollView* mLocalMap; - std::string mPrefix; - bool mChanged; - bool mFogOfWar; - - void applyFogOfWar(); - - OEngine::GUI::Layout* mLayout; - - float mLastPositionX; - float mLastPositionY; - float mLastDirectionX; - float mLastDirectionY; - }; - - class HUD : public OEngine::GUI::Layout, public LocalMapBase - { - public: - HUD(int width, int height, int fpsLevel); - void setStats(int h, int hmax, int m, int mmax, int s, int smax); - void setWeapIcon(const char *str); - void setSpellIcon(const char *str); - void setWeapStatus(int s, int smax); - void setSpellStatus(int s, int smax); - void setEffect(const char *img); - void setValue (const std::string& id, const MWMechanics::DynamicStat& value); - void setFPS(float fps); - void setTriangleCount(size_t count); - void setBatchCount(size_t count); - void setPlayerDir(const float x, const float y); - void setPlayerPos(const float x, const float y); - void setBottomLeftVisibility(bool hmsVisible, bool weapVisible, bool spellVisible); - void setBottomRightVisibility(bool effectBoxVisible, bool minimapVisible); - void setFpsLevel(const int level); - - MyGUI::ProgressPtr health, magicka, stamina; - MyGUI::Widget *weapBox, *spellBox; - MyGUI::ImageBox *weapImage, *spellImage; - MyGUI::ProgressPtr weapStatus, spellStatus; - MyGUI::Widget *effectBox, *minimapBox; - MyGUI::ImageBox* effect1; - MyGUI::ScrollView* minimap; - MyGUI::ImageBox* compass; - MyGUI::ImageBox* crosshair; - - MyGUI::WidgetPtr fpsbox; - MyGUI::TextBox* fpscounter; - MyGUI::TextBox* trianglecounter; - MyGUI::TextBox* batchcounter; - - private: - // bottom left elements - int hmsBaseLeft, weapBoxBaseLeft, spellBoxBaseLeft; - // bottom right elements - int minimapBoxBaseRight, effectBoxBaseRight; - }; - - class MainMenu : public OEngine::GUI::Layout - { - public: - MainMenu(int w, int h) - : Layout("openmw_mainmenu_layout.xml") - { - setCoord(0,0,w,h); - } - }; - -#if 0 - class InventoryWindow : public OEngine::GUI::Layout - { - public: - enum CategoryMode - { - CM_All = 0, // All items - CM_Weapon = 1, // Only weapons - CM_Apparel = 2, // Apparel - CM_Magic = 3, // Magic - CM_Misc = 4 // Misc - }; - - InventoryWindow () - : Layout("openmw_inventory_window_layout.xml") - , categoryMode(CM_All) - - // color should be fetched from skin - , activeColor(0, 0, 1) - , inactiveColor(0.7, 0.7, 0.7) - { - setCoord(0, 200, 600, 400); - - // These are just demo values, you should replace these with - // real calls from outside the class later. - - mMainWidget->setCaption("Glass Frostsword"); - setText("EncumbranceBarT", "176/210"); - - MyGUI::ProgressPtr pt; - getWidget(pt, "EncumbranceBar"); - pt->setProgressRange(210); - pt->setProgressPosition(176); - - MyGUI::WidgetPtr avatar; - getWidget(avatar, "Avatar"); - - // Adjust armor rating text to bottom of avatar widget - MyGUI::TextBox* armor_rating; - getWidget(armor_rating, "ArmorRating"); - armor_rating->setCaption("Armor: 11"); - MyGUI::IntCoord coord = armor_rating->getCoord(); - coord.top = avatar->getCoord().height - 4 - coord.height; - armor_rating->setCoord(coord); - - names[0] = "All"; - names[1] = "Weapon"; - names[2] = "Apparel"; - names[3] = "Magic"; - names[4] = "Misc"; - - boost::array categories = { { - CM_All, CM_Weapon, CM_Apparel, CM_Magic, CM_Misc - } }; - - // Initialize buttons with text and adjust sizes, also mark All as active button - int margin = 2; - int last_x = 0; - for (int i = 0; i < categories.size(); ++i) - { - CategoryMode mode = categories[i]; - std::string name = names[mode]; - name += "Button"; - setText(name, names[mode]); - getWidget(buttons[mode], name); - - MyGUI::ButtonPtr &button_pt = buttons[mode]; - if (mode == CM_All) - button_pt->setTextColour(activeColor); - else - button_pt->setTextColour(inactiveColor); - MyGUI::IntCoord coord = button_pt->getCoord(); - coord.left = last_x; - last_x += coord.width + margin; - button_pt->setCoord(coord); - - button_pt->eventMouseButtonClick += MyGUI::newDelegate(this, &InventoryWindow::onCategorySelected); - } - } - - void setCategory(CategoryMode mode) - { - MyGUI::ButtonPtr pt = getCategoryButton(categoryMode); - pt->setTextColour(inactiveColor); - - pt = getCategoryButton(mode); - pt->setTextColour(activeColor); - categoryMode = mode; - } - - MyGUI::ButtonPtr getCategoryButton(CategoryMode mode) - { - return buttons[mode]; - } - - void onCategorySelected(MyGUI::Widget *widget) - { - boost::array categories = { { - CM_All, CM_Weapon, CM_Apparel, CM_Magic, CM_Misc - } }; - - for (int i = 0; i < categories.size(); ++i) - { - CategoryMode mode = categories[i]; - if (widget == buttons[mode]) - { - setCategory(mode); - return; - } - } - } - - CategoryMode categoryMode; // Current category filter - MyGUI::ButtonPtr buttons[5]; // Button pointers - std::string names[5]; // Names of category buttons - - MyGUI::Colour activeColor; - MyGUI::Colour inactiveColor; - }; -#endif -} -#endif diff --git a/apps/openmw/mwgui/list.cpp b/apps/openmw/mwgui/list.cpp index d66cc6f89b..661fb2e683 100644 --- a/apps/openmw/mwgui/list.cpp +++ b/apps/openmw/mwgui/list.cpp @@ -28,8 +28,11 @@ void MWList::initialiseOverride() void MWList::addItem(const std::string& name) { mItems.push_back(name); +} - redraw(); +void MWList::addSeparator() +{ + mItems.push_back(""); } void MWList::adjustSize() @@ -52,22 +55,33 @@ void MWList::redraw(bool scrollbarShown) for (std::vector::const_iterator it=mItems.begin(); it!=mItems.end(); ++it) { - MyGUI::Button* button = mScrollView->createWidget( - "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), - MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); - button->setCaption((*it)); - button->getSubWidgetText()->setWordWrap(true); - button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); - button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); - button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); + if (*it != "") + { + MyGUI::Button* button = mScrollView->createWidget( + "MW_ListLine", MyGUI::IntCoord(0, mItemHeight, mScrollView->getSize().width - scrollBarWidth - 2, 24), + MyGUI::Align::Left | MyGUI::Align::Top, getName() + "_item_" + (*it)); + button->setCaption((*it)); + button->getSubWidgetText()->setWordWrap(true); + button->getSubWidgetText()->setTextAlign(MyGUI::Align::Left); + button->eventMouseWheel += MyGUI::newDelegate(this, &MWList::onMouseWheel); + button->eventMouseButtonClick += MyGUI::newDelegate(this, &MWList::onItemSelected); - int height = button->getTextSize().height; - button->setSize(MyGUI::IntSize(button->getSize().width, height)); + int height = button->getTextSize().height; + button->setSize(MyGUI::IntSize(button->getSize().width, height)); - mItemHeight += height + spacing; + mItemHeight += height + spacing; + } + else + { + MyGUI::ImageBox* separator = mScrollView->createWidget("MW_HLine", + MyGUI::IntCoord(2, mItemHeight, mScrollView->getWidth()-4, 18), + MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); + separator->setNeedMouseFocus(false); + + mItemHeight += 18 + spacing; + } } mScrollView->setCanvasSize(mClient->getSize().width + (_scrollBarWidth-scrollBarWidth), std::max(mItemHeight, mClient->getSize().height)); - mScrollView->setViewOffset(MyGUI::IntPoint(0,0)); if (!scrollbarShown && mItemHeight > mClient->getSize().height) redraw(true); @@ -93,15 +107,11 @@ void MWList::removeItem(const std::string& name) { assert( std::find(mItems.begin(), mItems.end(), name) != mItems.end() ); mItems.erase( std::find(mItems.begin(), mItems.end(), name) ); - - redraw(); } void MWList::clear() { mItems.clear(); - - redraw(); } void MWList::onMouseWheel(MyGUI::Widget* _sender, int _rel) diff --git a/apps/openmw/mwgui/list.hpp b/apps/openmw/mwgui/list.hpp index a2e9afcd1e..2b765c2e11 100644 --- a/apps/openmw/mwgui/list.hpp +++ b/apps/openmw/mwgui/list.hpp @@ -26,15 +26,16 @@ namespace MWGui EventHandle_String eventItemSelected; /** - * Call after the size of the list changed + * Call after the size of the list changed, or items were inserted/removed */ void adjustSize(); void addItem(const std::string& name); + void addSeparator(); ///< add a seperator between the current and the next item. void removeItem(const std::string& name); bool hasItem(const std::string& name); unsigned int getItemCount(); - std::string getItemNameAt(unsigned int at); + std::string getItemNameAt(unsigned int at); ///< \attention if there are separators, this method will return "" at the place where the separator is void clear(); protected: diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp new file mode 100644 index 0000000000..b32f2d900b --- /dev/null +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -0,0 +1,16 @@ +#include + +namespace MWGui +{ + + class MainMenu : public OEngine::GUI::Layout + { + public: + MainMenu(int w, int h) + : Layout("openmw_mainmenu_layout.xml") + { + setCoord(0,0,w,h); + } + }; + +} diff --git a/apps/openmw/mwgui/map_window.cpp b/apps/openmw/mwgui/map_window.cpp index e0c828fdc4..78ca707988 100644 --- a/apps/openmw/mwgui/map_window.cpp +++ b/apps/openmw/mwgui/map_window.cpp @@ -1,27 +1,100 @@ #include "map_window.hpp" #include "window_manager.hpp" -/* -#include "../mwmechanics/mechanicsmanager.hpp" -#include -#include -#include +#include -#undef min -#undef max -*/ using namespace MWGui; +LocalMapBase::LocalMapBase() + : mCurX(0) + , mCurY(0) + , mInterior(false) + , mFogOfWar(true) + , mLocalMap(NULL) + , mPrefix() + , mChanged(true) + , mLayout(NULL) + , mLastPositionX(0.0f) + , mLastPositionY(0.0f) + , mLastDirectionX(0.0f) + , mLastDirectionY(0.0f) +{ +} + +void LocalMapBase::init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout) +{ + mLocalMap = widget; + mLayout = layout; +} + +void LocalMapBase::setCellPrefix(const std::string& prefix) +{ + mPrefix = prefix; + mChanged = true; +} + +void LocalMapBase::toggleFogOfWar() +{ + mFogOfWar = !mFogOfWar; + applyFogOfWar(); +} + +void LocalMapBase::applyFogOfWar() +{ + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + std::string image = mPrefix+"_"+ boost::lexical_cast(mCurX + (mx-1)) + "_" + + boost::lexical_cast(mCurY + (mInterior ? (my-1) : -1*(my-1))); + MyGUI::ImageBox* fog; + mLayout->getWidget(fog, name+"_fog"); + fog->setImageTexture(mFogOfWar ? + ((MyGUI::RenderManager::getInstance().getTexture(image+"_fog") != 0) ? image+"_fog" + : "black.png" ) + : ""); + } + } +} + +void LocalMapBase::setActiveCell(const int x, const int y, bool interior) +{ + if (x==mCurX && y==mCurY && mInterior==interior && !mChanged) return; // don't do anything if we're still in the same cell + for (int mx=0; mx<3; ++mx) + { + for (int my=0; my<3; ++my) + { + std::string name = "Map_" + boost::lexical_cast(mx) + "_" + + boost::lexical_cast(my); + + std::string image = mPrefix+"_"+ boost::lexical_cast(x + (mx-1)) + "_" + + boost::lexical_cast(y + (interior ? (my-1) : -1*(my-1))); + + MyGUI::ImageBox* box; + mLayout->getWidget(box, name); + + if (MyGUI::RenderManager::getInstance().getTexture(image) != 0) + box->setImageTexture(image); + else + box->setImageTexture("black.png"); + } + } + mInterior = interior; + mCurX = x; + mCurY = y; + mChanged = false; + applyFogOfWar(); +} + +// ------------------------------------------------------------------------------------------ + MapWindow::MapWindow(WindowManager& parWindowManager) : MWGui::WindowPinnableBase("openmw_map_window_layout.xml", parWindowManager), mGlobal(false) { setCoord(500,0,320,300); - setText("WorldButton", "World"); - setImage("Compass", "textures\\compass.dds"); - - // Obviously you should override this later on - setCellName("No Cell Loaded"); getWidget(mLocalMap, "LocalMap"); getWidget(mGlobalMap, "GlobalMap"); @@ -43,8 +116,7 @@ MapWindow::MapWindow(WindowManager& parWindowManager) : void MapWindow::setCellName(const std::string& cellName) { - static_cast(mMainWidget)->setCaption(cellName); - adjustWindowCaption(); + setTitle(cellName); } void MapWindow::setPlayerPos(const float x, const float y) diff --git a/apps/openmw/mwgui/map_window.hpp b/apps/openmw/mwgui/map_window.hpp index d14221a408..e7318f4e45 100644 --- a/apps/openmw/mwgui/map_window.hpp +++ b/apps/openmw/mwgui/map_window.hpp @@ -1,11 +1,39 @@ #ifndef MWGUI_MAPWINDOW_H #define MWGUI_MAPWINDOW_H -#include "layouts.hpp" #include "window_pinnable_base.hpp" namespace MWGui { + class LocalMapBase + { + public: + LocalMapBase(); + void init(MyGUI::ScrollView* widget, OEngine::GUI::Layout* layout); + + void setCellPrefix(const std::string& prefix); + void setActiveCell(const int x, const int y, bool interior=false); + + void toggleFogOfWar(); + + protected: + int mCurX, mCurY; + bool mInterior; + MyGUI::ScrollView* mLocalMap; + std::string mPrefix; + bool mChanged; + bool mFogOfWar; + + void applyFogOfWar(); + + OEngine::GUI::Layout* mLayout; + + float mLastPositionX; + float mLastPositionY; + float mLastDirectionX; + float mLastDirectionY; + }; + class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase { public: diff --git a/apps/openmw/mwgui/messagebox.cpp b/apps/openmw/mwgui/messagebox.cpp index c103bcb8b8..a6b9025ce4 100644 --- a/apps/openmw/mwgui/messagebox.cpp +++ b/apps/openmw/mwgui/messagebox.cpp @@ -15,6 +15,13 @@ void MessageBoxManager::onFrame (float frameDuration) std::vector::iterator it; for(it = mTimers.begin(); it != mTimers.end();) { + // if this messagebox is already deleted, remove the timer and move on + if (std::find(mMessageBoxes.begin(), mMessageBoxes.end(), it->messageBox) == mMessageBoxes.end()) + { + it = mTimers.erase(it); + continue; + } + it->current += frameDuration; if(it->current >= it->max) { diff --git a/apps/openmw/mwgui/mode.hpp b/apps/openmw/mwgui/mode.hpp index fa31bb1c4e..775fe4a030 100644 --- a/apps/openmw/mwgui/mode.hpp +++ b/apps/openmw/mwgui/mode.hpp @@ -7,6 +7,7 @@ namespace MWGui { GM_Game, // Game mode, only HUD GM_Inventory, // Inventory mode + GM_Container, GM_MainMenu, // Main menu mode GM_Console, // Console mode diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 275759c9f7..f18bdb41ff 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -71,7 +71,6 @@ RaceDialog::RaceDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); MyGUI::ButtonPtr okButton; diff --git a/apps/openmw/mwgui/review.cpp b/apps/openmw/mwgui/review.cpp index 81a87b07b6..5059efb342 100644 --- a/apps/openmw/mwgui/review.cpp +++ b/apps/openmw/mwgui/review.cpp @@ -27,25 +27,21 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) ButtonPtr button; getWidget(nameWidget, "NameText"); getWidget(button, "NameButton"); - button->setCaption(mWindowManager.getGameSettingString("sName", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onNameClicked);; getWidget(raceWidget, "RaceText"); getWidget(button, "RaceButton"); - button->setCaption(mWindowManager.getGameSettingString("sRace", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onRaceClicked);; getWidget(classWidget, "ClassText"); getWidget(button, "ClassButton"); - button->setCaption(mWindowManager.getGameSettingString("sClass", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onClassClicked);; getWidget(birthSignWidget, "SignText"); getWidget(button, "SignButton"); - button->setCaption(mWindowManager.getGameSettingString("sBirthSign", "")); adjustButtonSize(button); button->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBirthSignClicked);; @@ -92,7 +88,6 @@ ReviewDialog::ReviewDialog(WindowManager& parWindowManager) MyGUI::ButtonPtr backButton; getWidget(backButton, "BackButton"); - backButton->setCaption(mWindowManager.getGameSettingString("sBack", "")); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &ReviewDialog::onBackClicked); MyGUI::ButtonPtr okButton; diff --git a/apps/openmw/mwgui/scrollwindow.cpp b/apps/openmw/mwgui/scrollwindow.cpp index 38e2f77c17..877864cfed 100644 --- a/apps/openmw/mwgui/scrollwindow.cpp +++ b/apps/openmw/mwgui/scrollwindow.cpp @@ -25,7 +25,8 @@ ScrollWindow::ScrollWindow (WindowManager& parWindowManager) : void ScrollWindow::open (MWWorld::Ptr scroll) { - MWBase::Environment::get().getSoundManager()->playSound3D (scroll, "scroll", 1.0, 1.0); + // no 3d sounds because the object could be in a container. + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); mScroll = scroll; @@ -41,18 +42,25 @@ void ScrollWindow::open (MWWorld::Ptr scroll) mTextView->setCanvasSize(410, mTextView->getSize().height); mTextView->setViewOffset(MyGUI::IntPoint(0,0)); + + setTakeButtonShow(true); +} + +void ScrollWindow::setTakeButtonShow(bool show) +{ + mTakeButton->setVisible(show); } void ScrollWindow::onCloseButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mScroll, "scroll", 1.0, 1.0); + MWBase::Environment::get().getSoundManager()->playSound ("scroll", 1.0, 1.0); MWBase::Environment::get().getInputManager()->setGuiMode (GM_Game); } void ScrollWindow::onTakeButtonClicked (MyGUI::Widget* _sender) { - MWBase::Environment::get().getSoundManager()->playSound3D (mScroll, "Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); + MWBase::Environment::get().getSoundManager()->playSound ("Item Book Up", 1.0, 1.0, MWSound::Play_NoTrack); MWWorld::ActionTake take(mScroll); take.execute(); diff --git a/apps/openmw/mwgui/scrollwindow.hpp b/apps/openmw/mwgui/scrollwindow.hpp index 918a3d3ef0..d58596b4be 100644 --- a/apps/openmw/mwgui/scrollwindow.hpp +++ b/apps/openmw/mwgui/scrollwindow.hpp @@ -11,7 +11,9 @@ namespace MWGui { public: ScrollWindow (WindowManager& parWindowManager); + void open (MWWorld::Ptr scroll); + void setTakeButtonShow(bool show); protected: void onCloseButtonClicked (MyGUI::Widget* _sender); diff --git a/apps/openmw/mwgui/stats_window.cpp b/apps/openmw/mwgui/stats_window.cpp index 1866682226..1dd82cf6ab 100644 --- a/apps/openmw/mwgui/stats_window.cpp +++ b/apps/openmw/mwgui/stats_window.cpp @@ -1,13 +1,19 @@ #include "stats_window.hpp" -#include "../mwmechanics/mechanicsmanager.hpp" -#include "window_manager.hpp" - #include #include #include + #include +#include "../mwmechanics/mechanicsmanager.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/player.hpp" +#include "../mwbase/environment.hpp" + +#include "window_manager.hpp" + + using namespace MWGui; const int StatsWindow::lineHeight = 18; @@ -24,11 +30,12 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) , skillValues() , skillWidgetMap() , factionWidgetMap() - , factions() + , mFactions() , birthSignId() , reputation(0) , bounty(0) , skillWidgets() + , mChanged(true) { setCoord(0,0,498, 342); @@ -42,12 +49,6 @@ StatsWindow::StatsWindow (WindowManager& parWindowManager) { "Attrib6", "sAttributeEndurance" }, { "Attrib7", "sAttributePersonality" }, { "Attrib8", "sAttributeLuck" }, - { "Health_str", "sHealth" }, - { "Magicka_str", "sMagic" }, - { "Fatigue_str", "sFatigue" }, - { "Level_str", "sLevel" }, - { "Race_str", "sRace" }, - { "Class_str", "sClass" }, { 0, 0 } }; @@ -171,11 +172,32 @@ void StatsWindow::setValue (const std::string& id, const MWMechanics::DynamicSta }; for (int i=0; ids[i]; ++i) + { if (ids[i]==id) { std::string id (ids[i]); setBar (id, id + "T", value.getCurrent(), value.getModified()); + + // health, magicka, fatigue tooltip + MyGUI::Widget* w; + std::string valStr = boost::lexical_cast(value.getCurrent()) + "/" + boost::lexical_cast(value.getModified()); + if (i==0) + { + getWidget(w, "Health"); + w->setUserString("Caption_HealthDescription", "#{sHealthDesc}\n" + valStr); + } + else if (i==1) + { + getWidget(w, "Magicka"); + w->setUserString("Caption_HealthDescription", "#{sIntDesc}\n" + valStr); + } + else if (i==2) + { + getWidget(w, "Fatigue"); + w->setUserString("Caption_HealthDescription", "#{sFatDesc}\n" + valStr); + } } + } } void StatsWindow::setValue (const std::string& id, const std::string& value) @@ -236,14 +258,38 @@ void StatsWindow::configureSkills (const std::vector& major, const std::vec } } -void StatsWindow::setFactions (const std::vector& factions) +void StatsWindow::onFrame () { - this->factions = factions; + if (mMainWidget->getVisible()) + return; + + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWMechanics::NpcStats PCstats = MWWorld::Class::get(player).getNpcStats(player); + + setFactions(PCstats.mFactionRank); + + setBirthSign(MWBase::Environment::get().getWorld()->getPlayer().getBirthsign()); + + if (mChanged) + updateSkillArea(); +} + +void StatsWindow::setFactions (const FactionList& factions) +{ + if (mFactions != factions) + { + mFactions = factions; + mChanged = true; + } } void StatsWindow::setBirthSign (const std::string& signId) { - birthSignId = signId; + if (signId != birthSignId) + { + birthSignId = signId; + mChanged = true; + } } void StatsWindow::addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -271,19 +317,15 @@ void StatsWindow::addGroup(const std::string &label, MyGUI::IntCoord &coord1, My coord2.top += lineHeight; } -MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox *skillNameWidget, *skillValueWidget; skillNameWidget = skillClientWidget->createWidget("SandText", coord1, MyGUI::Align::Left | MyGUI::Align::Top | MyGUI::Align::HStretch); skillNameWidget->setCaption(text); - skillNameWidget->setUserString("ToolTipType", "Text"); - skillNameWidget->setUserString("ToolTipText", tooltip); skillNameWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); skillValueWidget = skillClientWidget->createWidget("SandTextRight", coord2, MyGUI::Align::Right | MyGUI::Align::Top); - skillValueWidget->setUserString("ToolTipType", "Text"); - skillValueWidget->setUserString("ToolTipText", tooltip); skillValueWidget->setCaption(value); skillValueWidget->_setWidgetState(state); skillValueWidget->eventMouseWheel += MyGUI::newDelegate(this, &StatsWindow::onMouseWheel); @@ -297,7 +339,7 @@ MyGUI::TextBox* StatsWindow::addValueItem(const std::string& text, const std::st return skillValueWidget; } -void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) +MyGUI::Widget* StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) { MyGUI::TextBox* skillNameWidget; @@ -309,6 +351,8 @@ void StatsWindow::addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI coord1.top += lineHeight; coord2.top += lineHeight; + + return skillNameWidget; } void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2) @@ -333,25 +377,52 @@ void StatsWindow::addSkills(const SkillList &skills, const std::string &titleId, float base = stat.getBase(); float modified = stat.getModified(); + const ESM::Skill* skill = mWindowManager.getStore().skills.search(skillId); + assert(skill); + + std::string icon = "icons\\k\\" + ESM::Skill::sIconNames[skillId]; + + const ESM::Attribute* attr = mWindowManager.getStore().attributes.search(skill->data.attribute); + assert(attr); + std::string state = "normal"; if (modified > base) state = "increased"; else if (modified < base) state = "decreased"; - MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), "", + MyGUI::TextBox* widget = addValueItem(mWindowManager.getGameSettingString(skillNameId, skillNameId), boost::lexical_cast(static_cast(modified)), state, coord1, coord2); + + for (int i=0; i<2; ++i) + { + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "SkillToolTip"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillName", "#{"+skillNameId+"}"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillDescription", skill->description); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillAttribute", "#{sGoverningAttribute}: #{" + attr->name + "}"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ImageTexture_SkillImage", icon); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_SkillProgressText", "0/100"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Range_SkillProgress", "100"); + } + skillWidgetMap[skillId] = widget; } } void StatsWindow::updateSkillArea() { + mChanged = false; + for (std::vector::iterator it = skillWidgets.begin(); it != skillWidgets.end(); ++it) { MyGUI::Gui::getInstance().destroyWidget(*it); } skillWidgets.clear(); + skillScrollerWidget->setScrollPosition(0); + onScrollChangePosition(skillScrollerWidget, 0); + clientHeight = 0; + const int valueSize = 40; MyGUI::IntCoord coord1(10, 0, skillClientWidget->getWidth() - (10 + valueSize), 18); MyGUI::IntCoord coord2(coord1.left + coord1.width, coord1.top, valueSize, coord1.height); @@ -367,19 +438,90 @@ void StatsWindow::updateSkillArea() const ESMS::ESMStore &store = mWindowManager.getStore(); - if (!factions.empty()) + // race tooltip + const ESM::Race* playerRace = store.races.find (MWBase::Environment::get().getWorld()->getPlayer().getRace()); + MyGUI::Widget* raceWidget; + getWidget(raceWidget, "RaceText"); + raceWidget->setUserString("Caption_CenteredCaption", playerRace->name); + raceWidget->setUserString("Caption_CenteredCaptionText", playerRace->description); + getWidget(raceWidget, "Race_str"); + raceWidget->setUserString("Caption_CenteredCaption", playerRace->name); + raceWidget->setUserString("Caption_CenteredCaptionText", playerRace->description); + + // class tooltip + MyGUI::Widget* classWidget; + const ESM::Class& playerClass = MWBase::Environment::get().getWorld()->getPlayer().getClass(); + int spec = playerClass.data.specialization; + std::string specStr; + if (spec == 0) + specStr = "#{sSpecializationCombat}"; + else if (spec == 1) + specStr = "#{sSpecializationMagic}"; + else if (spec == 2) + specStr = "#{sSpecializationStealth}"; + + getWidget(classWidget, "ClassText"); + classWidget->setUserString("Caption_ClassName", playerClass.name); + classWidget->setUserString("Caption_ClassDescription", playerClass.description); + classWidget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + getWidget(classWidget, "Class_str"); + classWidget->setUserString("Caption_ClassName", playerClass.name); + classWidget->setUserString("Caption_ClassDescription", playerClass.description); + classWidget->setUserString("Caption_ClassSpecialisation", "#{sSpecialization}: " + specStr); + + if (!mFactions.empty()) { // Add a line separator if there are items above if (!skillWidgets.empty()) addSeparator(coord1, coord2); addGroup(mWindowManager.getGameSettingString("sFaction", "Faction"), coord1, coord2); - FactionList::const_iterator end = factions.end(); - for (FactionList::const_iterator it = factions.begin(); it != end; ++it) + FactionList::const_iterator end = mFactions.end(); + for (FactionList::const_iterator it = mFactions.begin(); it != end; ++it) { const ESM::Faction *faction = store.factions.find(it->first); - addItem(faction->name, coord1, coord2); - // TODO: Faction rank should be placed in tooltip + MyGUI::Widget* w = addItem(faction->name, coord1, coord2); + + std::string text; + + text += std::string("#DDC79E") + faction->name; + text += std::string("\n#BF9959") + faction->ranks[it->second]; + + if (it->second < 9) + { + // player doesn't have max rank yet + text += std::string("\n\n#DDC79E#{sNextRank} ") + faction->ranks[it->second+1]; + + ESM::RankData rankData = faction->data.rankData[it->second+1]; + const ESM::Attribute* attr1 = mWindowManager.getStore().attributes.search(faction->data.attribute1); + const ESM::Attribute* attr2 = mWindowManager.getStore().attributes.search(faction->data.attribute2); + assert(attr1 && attr2); + + text += "\n#BF9959#{" + attr1->name + "}: " + boost::lexical_cast(rankData.attribute1) + + ", #{" + attr2->name + "}: " + boost::lexical_cast(rankData.attribute2); + + text += "\n\n#DDC79E#{sFavoriteSkills}"; + text += "\n#BF9959"; + for (int i=0; i<6; ++i) + { + const ESM::Skill* skill = mWindowManager.getStore().skills.search(faction->data.skillID[i]); + assert(skill); + text += "#{"+ESM::Skill::sSkillNameIds[faction->data.skillID[i]]+"}"; + if (i<5) + text += ", "; + } + + text += "\n"; + + if (rankData.skill1 > 0) + text += "\n#{sNeedOneSkill} " + boost::lexical_cast(rankData.skill1); + if (rankData.skill2 > 0) + text += "\n#{sNeedTwoSkills} " + boost::lexical_cast(rankData.skill2); + } + + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "TextToolTip"); + w->setUserString("Caption_Text", text); } } @@ -391,7 +533,62 @@ void StatsWindow::updateSkillArea() addGroup(mWindowManager.getGameSettingString("sBirthSign", "Sign"), coord1, coord2); const ESM::BirthSign *sign = store.birthSigns.find(birthSignId); - addItem(sign->name, coord1, coord2); + MyGUI::Widget* w = addItem(sign->name, coord1, coord2); + w->setUserString("ToolTipType", "Layout"); + w->setUserString("ToolTipLayout", "BirthSignToolTip"); + std::string image = sign->texture; + image.replace(image.size()-3, 3, "dds"); + w->setUserString("ImageTexture_BirthSignImage", "textures\\" + image); + std::string text; + + text += sign->name; + text += "\n#BF9959" + sign->description; + + std::vector abilities, powers, spells; + + std::vector::const_iterator it = sign->powers.list.begin(); + std::vector::const_iterator end = sign->powers.list.end(); + for (; it != end; ++it) + { + const std::string &spellId = *it; + const ESM::Spell *spell = store.spells.search(spellId); + if (!spell) + continue; // Skip spells which cannot be found + ESM::Spell::SpellType type = static_cast(spell->data.type); + if (type != ESM::Spell::ST_Spell && type != ESM::Spell::ST_Ability && type != ESM::Spell::ST_Power) + continue; // We only want spell, ability and powers. + + if (type == ESM::Spell::ST_Ability) + abilities.push_back(spellId); + else if (type == ESM::Spell::ST_Power) + powers.push_back(spellId); + else if (type == ESM::Spell::ST_Spell) + spells.push_back(spellId); + } + + struct{ const std::vector &spells; std::string label; } categories[3] = { + {abilities, "sBirthsignmenu1"}, + {powers, "sPowers"}, + {spells, "sBirthsignmenu2"} + }; + + for (int category = 0; category < 3; ++category) + { + for (std::vector::const_iterator it = categories[category].spells.begin(); it != categories[category].spells.end(); ++it) + { + if (it == categories[category].spells.begin()) + { + text += std::string("\n#DDC79E") + std::string("#{") + categories[category].label + "}"; + } + + const std::string &spellId = *it; + + const ESM::Spell *spell = store.spells.search(spellId); + text += "\n#BF9959" + spell->name; + } + } + + w->setUserString("Caption_BirthSignText", text); } // Add a line separator if there are items above @@ -399,12 +596,25 @@ void StatsWindow::updateSkillArea() addSeparator(coord1, coord2); addValueItem(mWindowManager.getGameSettingString("sReputation", "Reputation"), - mWindowManager.getGameSettingString("sSkillsMenuReputationHelp", ""), boost::lexical_cast(static_cast(reputation)), "normal", coord1, coord2); + + for (int i=0; i<2; ++i) + { + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sSkillsMenuReputationHelp}"); + } + addValueItem(mWindowManager.getGameSettingString("sBounty", "Bounty"), - mWindowManager.getGameSettingString("sCrimeHelp", ""), boost::lexical_cast(static_cast(bounty)), "normal", coord1, coord2); + for (int i=0; i<2; ++i) + { + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipType", "Layout"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("ToolTipLayout", "TextToolTip"); + skillWidgets[skillWidgets.size()-1-i]->setUserString("Caption_Text", "#{sCrimeHelp}"); + } + clientHeight = coord1.top; updateScroller(); } @@ -428,91 +638,109 @@ void StatsWindow::setupToolTips() const ESMS::ESMStore &store = mWindowManager.getStore(); MyGUI::Widget* widget; + /// \todo move this into the .layout file! + getWidget(widget, "Attrib1"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_strength.dds"); getWidget(widget, "AttribVal1"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeStrength")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sStrDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_strength.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeStrength")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sStrDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_strength.dds"); getWidget(widget, "Attrib2"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_int.dds"); getWidget(widget, "AttribVal2"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeIntelligence")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sIntDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_int.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeIntelligence")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sIntDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_int.dds"); getWidget(widget, "Attrib3"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_wilpower.dds"); getWidget(widget, "AttribVal3"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeWillpower")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sWilDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_wilpower.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeWillpower")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sWilDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_wilpower.dds"); getWidget(widget, "Attrib4"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_agility.dds"); getWidget(widget, "AttribVal4"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeAgility")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sAgiDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_agility.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeAgility")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sAgiDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_agility.dds"); getWidget(widget, "Attrib5"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_speed.dds"); getWidget(widget, "AttribVal5"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeSpeed")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sSpdDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_speed.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeSpeed")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sSpdDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_speed.dds"); getWidget(widget, "Attrib6"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_endurance.dds"); getWidget(widget, "AttribVal6"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeEndurance")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sEndDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_endurance.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeEndurance")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sEndDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_endurance.dds"); getWidget(widget, "Attrib7"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_personality.dds"); getWidget(widget, "AttribVal7"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributePersonality")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sPerDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_personality.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributePersonality")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sPerDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_personality.dds"); getWidget(widget, "Attrib8"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_luck.dds"); getWidget(widget, "AttribVal8"); - widget->setUserString("ToolTipType", "ImageCaptionText"); - widget->setUserString("ToolTipCaption", store.gameSettings.find ("sAttributeLuck")->str); - widget->setUserString("ToolTipText", store.gameSettings.find ("sLucDesc")->str); - widget->setUserString("ToolTipImage", "k\\attribute_luck.dds"); + widget->setUserString("ToolTipType", "Layout"); + widget->setUserString("ToolTipLayout", "AttributeToolTip"); + widget->setUserString("Caption_AttributeName", store.gameSettings.find ("sAttributeLuck")->str); + widget->setUserString("Caption_AttributeDescription", store.gameSettings.find ("sLucDesc")->str); + widget->setUserString("ImageTexture_AttributeImage", "icons\\k\\attribute_luck.dds"); } diff --git a/apps/openmw/mwgui/stats_window.hpp b/apps/openmw/mwgui/stats_window.hpp index 08c5148ecc..50a83bb29e 100644 --- a/apps/openmw/mwgui/stats_window.hpp +++ b/apps/openmw/mwgui/stats_window.hpp @@ -18,13 +18,15 @@ namespace MWGui class StatsWindow : public WindowPinnableBase { public: - typedef std::pair Faction; - typedef std::vector FactionList; + typedef std::map FactionList; typedef std::vector SkillList; StatsWindow(WindowManager& parWindowManager); + /// automatically updates all the data in the stats window, but only if it has changed. + void onFrame(); + void setBar(const std::string& name, const std::string& tname, int val, int max); void setPlayerName(const std::string& playerName); @@ -36,8 +38,6 @@ namespace MWGui void setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::Stat& value); void configureSkills (const SkillList& major, const SkillList& minor); - void setFactions (const std::vector& factions); - void setBirthSign (const std::string &signId); void setReputation (int reputation) { this->reputation = reputation; } void setBounty (int bounty) { this->bounty = bounty; } void updateSkillArea(); @@ -46,12 +46,15 @@ namespace MWGui void addSkills(const SkillList &skills, const std::string &titleId, const std::string &titleDefault, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addSeparator(MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void addGroup(const std::string &label, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - MyGUI::TextBox* addValueItem(const std::string& text, const std::string& tooltip, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); - void addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::TextBox* addValueItem(const std::string& text, const std::string &value, const std::string& state, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); + MyGUI::Widget* addItem(const std::string text, MyGUI::IntCoord &coord1, MyGUI::IntCoord &coord2); void updateScroller(); void setupToolTips(); + void setFactions (const FactionList& factions); + void setBirthSign (const std::string &signId); + void onScrollChangePosition(MyGUI::ScrollBar* scroller, size_t pos); void onWindowResize(MyGUI::Window* window); void onMouseWheel(MyGUI::Widget* _sender, int _rel); @@ -69,11 +72,13 @@ namespace MWGui std::map > skillValues; std::map skillWidgetMap; std::map factionWidgetMap; - FactionList factions; ///< Stores a list of factions and the current rank + FactionList mFactions; ///< Stores a list of factions and the current rank std::string birthSignId; int reputation, bounty; std::vector skillWidgets; //< Skills and other information + bool mChanged; + protected: virtual void onPinToggled(); }; diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index 1dbe909681..3ade598baa 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -16,6 +16,9 @@ ToolTips::ToolTips(WindowManager* windowManager) : , mGameMode(true) , mWindowManager(windowManager) , mFullHelp(false) + , mEnabled(true) + , mFocusToolTipX(0.0) + , mFocusToolTipY(0.0) { getWidget(mDynamicToolTipBox, "DynamicToolTipBox"); @@ -27,23 +30,36 @@ ToolTips::ToolTips(WindowManager* windowManager) : mMainWidget->setNeedMouseFocus(false); } +void ToolTips::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + void ToolTips::onFrame(float frameDuration) { - /// \todo Store a MWWorld::Ptr in the widget user data, retrieve it here and construct a tooltip dynamically - MyGUI::Gui::getInstance().destroyWidget(mDynamicToolTipBox); mDynamicToolTipBox = mMainWidget->createWidget("HUD_Box", IntCoord(0, 0, mMainWidget->getCoord().width, mMainWidget->getCoord().height), Align::Stretch, "DynamicToolTipBox"); + // start by hiding everything + for (unsigned int i=0; i < mMainWidget->getChildCount(); ++i) + { + mMainWidget->getChildAt(i)->setVisible(false); + } + const IntSize &viewSize = RenderManager::getInstance().getViewSize(); + if (!mEnabled) + { + return; + } + if (!mGameMode) { Widget* focus = InputManager::getInstance().getMouseFocusWidget(); if (focus == 0) { - mDynamicToolTipBox->setVisible(false); return; } @@ -55,30 +71,77 @@ void ToolTips::onFrame(float frameDuration) ToolTipInfo info; if (type == "") { - mDynamicToolTipBox->setVisible(false); return; - } - else if (type == "Text") - { - info.text = text; } - else if (type == "CaptionText") + else if (type == "ItemPtr") { - std::string caption = focus->getUserString("ToolTipCaption"); - info.caption = caption; - info.text = text; + mFocusObject = *focus->getUserData(); + tooltipSize = getToolTipViaPtr(false); } - else if (type == "ImageCaptionText") + else if (type == "Layout") { - std::string caption = focus->getUserString("ToolTipCaption"); - std::string image = focus->getUserString("ToolTipImage"); - std::string sizeString = focus->getUserString("ToolTipImageSize"); + // tooltip defined in the layout + MyGUI::Widget* tooltip; + getWidget(tooltip, focus->getUserString("ToolTipLayout")); - info.text = text; - info.caption = caption; - info.icon = image; + tooltip->setVisible(true); + if (!tooltip->isUserString("DontResize")) + { + tooltip->setCoord(0, 0, 450, 300); // this is the maximum width of the tooltip before it starts word-wrapping + + tooltipSize = MyGUI::IntSize(0, tooltip->getSize().height); + } + else + tooltipSize = tooltip->getSize(); + + std::map userStrings = focus->getUserStrings(); + for (std::map::iterator it = userStrings.begin(); + it != userStrings.end(); ++it) + { + if (it->first == "ToolTipType" + || it->first == "ToolTipLayout") + continue; + + + size_t underscorePos = it->first.find("_"); + std::string propertyKey = it->first.substr(0, underscorePos); + std::string widgetName = it->first.substr(underscorePos+1, it->first.size()-(underscorePos+1)); + + MyGUI::Widget* w; + getWidget(w, widgetName); + w->setProperty(propertyKey, it->second); + } + + for (unsigned int i=0; igetChildCount(); ++i) + { + MyGUI::Widget* w = tooltip->getChildAt(i); + + if (w->isUserString("AutoResizeHorizontal")) + { + MyGUI::TextBox* text = w->castType(); + tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + text->getTextSize().width + 8); + } + else if (!tooltip->isUserString("DontResize")) + tooltipSize.width = std::max(tooltipSize.width, w->getLeft() + w->getWidth() + 8); + + if (w->isUserString("AutoResizeVertical")) + { + MyGUI::TextBox* text = w->castType(); + int height = text->getTextSize().height; + if (height > w->getHeight()) + { + tooltipSize += MyGUI::IntSize(0, height - w->getHeight()); + } + if (height < w->getHeight()) + { + tooltipSize -= MyGUI::IntSize(0, w->getHeight() - height); + } + } + } + tooltip->setCoord(0, 0, tooltipSize.width, tooltipSize.height); } - tooltipSize = createToolTip(info); + else + throw std::runtime_error ("unknown tooltip type"); IntPoint tooltipPosition = InputManager::getInstance().getMousePosition() + IntPoint(0, 24); @@ -93,7 +156,6 @@ void ToolTips::onFrame(float frameDuration) } setCoord(tooltipPosition.left, tooltipPosition.top, tooltipSize.width, tooltipSize.height); - mDynamicToolTipBox->setVisible(true); } else { @@ -101,15 +163,13 @@ void ToolTips::onFrame(float frameDuration) { IntSize tooltipSize = getToolTipViaPtr(); - // adjust tooltip size to fit its content, position it above the crosshair - /// \todo Slide the tooltip along the bounding box of the focused object (like in Morrowind) - setCoord(std::max(0, viewSize.width/2 - (tooltipSize.width)/2), - std::max(0, viewSize.height/2 - (tooltipSize.height) - 32), + setCoord(viewSize.width/2 - tooltipSize.width/2, + std::max(0, int(mFocusToolTipY*viewSize.height - tooltipSize.height)), tooltipSize.width, tooltipSize.height); + + mDynamicToolTipBox->setVisible(true); } - else - mDynamicToolTipBox->setVisible(false); } } @@ -128,7 +188,7 @@ void ToolTips::setFocusObject(const MWWorld::Ptr& focus) mFocusObject = focus; } -IntSize ToolTips::getToolTipViaPtr () +IntSize ToolTips::getToolTipViaPtr (bool image) { // this the maximum width of the tooltip before it starts word-wrapping setCoord(0, 0, 300, 300); @@ -145,6 +205,8 @@ IntSize ToolTips::getToolTipViaPtr () mDynamicToolTipBox->setVisible(true); ToolTipInfo info = object.getToolTipInfo(mFocusObject); + if (!image) + info.icon = ""; tooltipSize = createToolTip(info); } @@ -165,8 +227,10 @@ void ToolTips::findImageExtension(std::string& image) } } -IntSize ToolTips::createToolTip(const ToolTipInfo& info) +IntSize ToolTips::createToolTip(const MWGui::ToolTipInfo& info) { + mDynamicToolTipBox->setVisible(true); + std::string caption = info.caption; std::string image = info.icon; int imageSize = (image != "") ? 32 : 0; @@ -279,6 +343,9 @@ IntSize ToolTips::createToolTip(const ToolTipInfo& info) const int chargeTextWidth = chargeText->getTextSize().width + 5; const int chargeAndTextWidth = chargeWidth + chargeTextWidth; + + totalSize.width = std::max(totalSize.width, chargeAndTextWidth); + chargeText->setCoord((totalSize.width - chargeAndTextWidth)/2, coord.top+6, chargeTextWidth, 18); IntCoord chargeCoord; @@ -350,6 +417,14 @@ std::string ToolTips::getMiscString(const std::string& text, const std::string& return "\n" + prefix + ": " + text; } +std::string ToolTips::getCountString(const int value) +{ + if (value == 1) + return ""; + else + return " (" + boost::lexical_cast(value) + ")"; +} + void ToolTips::toggleFullHelp() { mFullHelp = !mFullHelp; @@ -359,3 +434,9 @@ bool ToolTips::getFullHelp() const { return mFullHelp; } + +void ToolTips::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) +{ + mFocusToolTipX = (min_x + max_x) / 2; + mFocusToolTipY = min_y; +} diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index fafe471a57..4be0baff9d 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -39,10 +39,14 @@ namespace MWGui void enterGameMode(); void enterGuiMode(); + void setEnabled(bool enabled); + void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) bool getFullHelp() const; void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); + ///< set the screen-space position of the tooltip for focused object static std::string getValueString(const int value, const std::string& prefix); ///< @return "prefix: value" or "" if value is 0 @@ -53,6 +57,9 @@ namespace MWGui static std::string toString(const float value); static std::string toString(const int value); + static std::string getCountString(const int value); + ///< @return blank string if count is 1, or else " (value)" + private: MyGUI::Widget* mDynamicToolTipBox; @@ -62,14 +69,19 @@ namespace MWGui void findImageExtension(std::string& image); - MyGUI::IntSize getToolTipViaPtr (); + MyGUI::IntSize getToolTipViaPtr (bool image=true); ///< @return requested tooltip size MyGUI::IntSize createToolTip(const ToolTipInfo& info); ///< @return requested tooltip size + float mFocusToolTipX; + float mFocusToolTipY; + bool mGameMode; + bool mEnabled; + bool mFullHelp; }; } diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp new file mode 100644 index 0000000000..60cc06cb86 --- /dev/null +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -0,0 +1,359 @@ +#include "tradewindow.hpp" + +#include + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/manualref.hpp" +#include "../mwsound/soundmanager.hpp" + +#include "window_manager.hpp" +#include "inventorywindow.hpp" + +namespace MWGui +{ + TradeWindow::TradeWindow(WindowManager& parWindowManager) : + WindowBase("openmw_trade_window_layout.xml", parWindowManager) + , ContainerBase(NULL) // no drag&drop + , mCurrentBalance(0) + { + MyGUI::ScrollView* itemView; + MyGUI::Widget* containerWidget; + getWidget(containerWidget, "Items"); + getWidget(itemView, "ItemView"); + setWidgets(containerWidget, itemView); + + getWidget(mFilterAll, "AllButton"); + getWidget(mFilterWeapon, "WeaponButton"); + getWidget(mFilterApparel, "ApparelButton"); + getWidget(mFilterMagic, "MagicButton"); + getWidget(mFilterMisc, "MiscButton"); + + getWidget(mMaxSaleButton, "MaxSaleButton"); + getWidget(mCancelButton, "CancelButton"); + getWidget(mOfferButton, "OfferButton"); + getWidget(mPlayerGold, "PlayerGold"); + getWidget(mMerchantGold, "MerchantGold"); + getWidget(mIncreaseButton, "IncreaseButton"); + getWidget(mDecreaseButton, "DecreaseButton"); + getWidget(mTotalBalance, "TotalBalance"); + getWidget(mTotalBalanceLabel, "TotalBalanceLabel"); + getWidget(mBottomPane, "BottomPane"); + + // adjust size of buttons to fit text + int curX = 0; + mFilterAll->setSize( mFilterAll->getTextSize().width + 24, mFilterAll->getSize().height ); + curX += mFilterAll->getTextSize().width + 24 + 4; + + mFilterWeapon->setPosition(curX, mFilterWeapon->getPosition().top); + mFilterWeapon->setSize( mFilterWeapon->getTextSize().width + 24, mFilterWeapon->getSize().height ); + curX += mFilterWeapon->getTextSize().width + 24 + 4; + + mFilterApparel->setPosition(curX, mFilterApparel->getPosition().top); + mFilterApparel->setSize( mFilterApparel->getTextSize().width + 24, mFilterApparel->getSize().height ); + curX += mFilterApparel->getTextSize().width + 24 + 4; + + mFilterMagic->setPosition(curX, mFilterMagic->getPosition().top); + mFilterMagic->setSize( mFilterMagic->getTextSize().width + 24, mFilterMagic->getSize().height ); + curX += mFilterMagic->getTextSize().width + 24 + 4; + + mFilterMisc->setPosition(curX, mFilterMisc->getPosition().top); + mFilterMisc->setSize( mFilterMisc->getTextSize().width + 24, mFilterMisc->getSize().height ); + + mFilterAll->setStateSelected(true); + + mFilterAll->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterWeapon->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterApparel->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterMagic->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + mFilterMisc->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onFilterChanged); + + mCancelButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onCancelButtonClicked); + mOfferButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TradeWindow::onOfferButtonClicked); + + mMaxSaleButton->setSize(MyGUI::IntSize(mMaxSaleButton->getTextSize().width + 24, mMaxSaleButton->getHeight())); + + int cancelButtonWidth = mCancelButton->getTextSize().width + 24; + mCancelButton->setCoord(mBottomPane->getWidth()-cancelButtonWidth, + mCancelButton->getTop(), + cancelButtonWidth, + mCancelButton->getHeight()); + + int offerButtonWidth = mOfferButton->getTextSize().width + 24; + mOfferButton->setCoord(mBottomPane->getWidth()-cancelButtonWidth-offerButtonWidth-8, + mOfferButton->getTop(), + offerButtonWidth, + mOfferButton->getHeight()); + + setCoord(400, 0, 400, 300); + + static_cast(mMainWidget)->eventWindowChangeCoord += MyGUI::newDelegate(this, &TradeWindow::onWindowResize); + } + + void TradeWindow::startTrade(MWWorld::Ptr actor) + { + setTitle(MWWorld::Class::get(actor).getName(actor)); + + mCurrentBalance = 0; + + mWindowManager.getInventoryWindow()->startTrade(); + + mBoughtItems.clear(); + + ContainerBase::openContainer(actor); + + updateLabels(); + } + + void TradeWindow::onFilterChanged(MyGUI::Widget* _sender) + { + if (_sender == mFilterAll) + setFilter(ContainerBase::Filter_All); + else if (_sender == mFilterWeapon) + setFilter(ContainerBase::Filter_Weapon); + else if (_sender == mFilterApparel) + setFilter(ContainerBase::Filter_Apparel); + else if (_sender == mFilterMagic) + setFilter(ContainerBase::Filter_Magic); + else if (_sender == mFilterMisc) + setFilter(ContainerBase::Filter_Misc); + + mFilterAll->setStateSelected(false); + mFilterWeapon->setStateSelected(false); + mFilterApparel->setStateSelected(false); + mFilterMagic->setStateSelected(false); + mFilterMisc->setStateSelected(false); + + static_cast(_sender)->setStateSelected(true); + } + + void TradeWindow::onWindowResize(MyGUI::Window* _sender) + { + drawItems(); + } + + void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) + { + // were there any items traded at all? + MWWorld::ContainerStore& playerBought = mWindowManager.getInventoryWindow()->getBoughtItems(); + MWWorld::ContainerStore& merchantBought = getBoughtItems(); + if (playerBought.begin() == playerBought.end() && merchantBought.begin() == merchantBought.end()) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog11")->str, std::vector()); + return; + } + + // check if the player can afford this + if (mCurrentBalance < 0 && mWindowManager.getInventoryWindow()->getPlayerGold() < std::abs(mCurrentBalance)) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog1")->str, std::vector()); + return; + } + + // check if the merchant can afford this + int merchantgold; + if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->npdt52.gold == -10) + merchantgold = ref->base->npdt12.gold; + else + merchantgold = ref->base->npdt52.gold; + } + else // ESM::Creature + { + ESMS::LiveCellRef* ref = mContainer.get(); + merchantgold = ref->base->data.gold; + } + if (mCurrentBalance > 0 && merchantgold < mCurrentBalance) + { + // user notification + MWBase::Environment::get().getWindowManager()-> + messageBox(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sBarterDialog2")->str, std::vector()); + return; + } + + // success! make the item transfer. + transferBoughtItems(); + mWindowManager.getInventoryWindow()->transferBoughtItems(); + + // add or remove gold from the player. + bool goldFound = false; + MWWorld::Ptr gold; + MWWorld::ContainerStore& playerStore = mWindowManager.getInventoryWindow()->getContainerStore(); + for (MWWorld::ContainerStoreIterator it = playerStore.begin(); + it != playerStore.end(); ++it) + { + if (MWWorld::Class::get(*it).getName(*it) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + goldFound = true; + gold = *it; + } + } + if (goldFound) + { + gold.getRefData().setCount(gold.getRefData().getCount() + mCurrentBalance); + } + else + { + assert(mCurrentBalance > 0); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); + ref.getPtr().getRefData().setCount(mCurrentBalance); + playerStore.add(ref.getPtr()); + } + + std::string sound = "Item Gold Up"; + MWBase::Environment::get().getSoundManager()->playSound (sound, 1.0, 1.0); + + mWindowManager.setGuiMode(GM_Game); + } + + void TradeWindow::onCancelButtonClicked(MyGUI::Widget* _sender) + { + // i give you back your stuff! + returnBoughtItems(mWindowManager.getInventoryWindow()->getContainerStore()); + // now gimme back my stuff! + mWindowManager.getInventoryWindow()->returnBoughtItems(MWWorld::Class::get(mContainer).getContainerStore(mContainer)); + + mWindowManager.setGuiMode(GM_Game); + } + + void TradeWindow::updateLabels() + { + mPlayerGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sYourGold")->str + + " " + boost::lexical_cast(mWindowManager.getInventoryWindow()->getPlayerGold())); + + if (mCurrentBalance > 0) + { + mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalSold")->str); + mTotalBalance->setCaption(boost::lexical_cast(mCurrentBalance)); + } + else + { + mTotalBalanceLabel->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sTotalCost")->str); + mTotalBalance->setCaption(boost::lexical_cast(-mCurrentBalance)); + } + + int merchantgold; + if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->npdt52.gold == -10) + merchantgold = ref->base->npdt12.gold; + else + merchantgold = ref->base->npdt52.gold; + } + else // ESM::Creature + { + ESMS::LiveCellRef* ref = mContainer.get(); + merchantgold = ref->base->data.gold; + } + + mMerchantGold->setCaption(MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sSellerGold")->str + + " " + boost::lexical_cast(merchantgold)); + } + + std::vector TradeWindow::getEquippedItems() + { + std::vector items; + + if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + { + // creatures don't have equipment slots. + return items; + } + + MWWorld::InventoryStore& invStore = MWWorld::Class::get(mContainer).getInventoryStore(mContainer); + + for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot) + { + MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); + if (it != invStore.end()) + { + items.push_back(*it); + } + } + + return items; + } + + bool TradeWindow::npcAcceptsItem(MWWorld::Ptr item) + { + int services = 0; + if (mContainer.getTypeName() == typeid(ESM::NPC).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + else if (mContainer.getTypeName() == typeid(ESM::Creature).name()) + { + ESMS::LiveCellRef* ref = mContainer.get(); + if (ref->base->hasAI) + services = ref->base->AI.services; + } + + if (item.getTypeName() == typeid(ESM::Weapon).name()) + return services & ESM::NPC::Weapon; + else if (item.getTypeName() == typeid(ESM::Armor).name()) + return services & ESM::NPC::Armor; + else if (item.getTypeName() == typeid(ESM::Clothing).name()) + return services & ESM::NPC::Clothing; + else if (item.getTypeName() == typeid(ESM::Book).name()) + return services & ESM::NPC::Books; + else if (item.getTypeName() == typeid(ESM::Ingredient).name()) + return services & ESM::NPC::Ingredients; + else if (item.getTypeName() == typeid(ESM::Tool).name()) + return services & ESM::NPC::Picks; + else if (item.getTypeName() == typeid(ESM::Probe).name()) + return services & ESM::NPC::Probes; + else if (item.getTypeName() == typeid(ESM::Light).name()) + return services & ESM::NPC::Lights; + else if (item.getTypeName() == typeid(ESM::Apparatus).name()) + return services & ESM::NPC::Apparatus; + else if (item.getTypeName() == typeid(ESM::Repair).name()) + return services & ESM::NPC::RepairItem; + else if (item.getTypeName() == typeid(ESM::Miscellaneous).name()) + return services & ESM::NPC::Misc; + + return false; + } + + std::vector TradeWindow::itemsToIgnore() + { + std::vector items; + MWWorld::ContainerStore& invStore = MWWorld::Class::get(mContainer).getContainerStore(mContainer); + + for (MWWorld::ContainerStoreIterator it = invStore.begin(); + it != invStore.end(); ++it) + { + if (!npcAcceptsItem(*it)) + items.push_back(*it); + } + + return items; + } + + void TradeWindow::sellToNpc(MWWorld::Ptr item, int count) + { + /// \todo price adjustment depending on merchantile skill + + mCurrentBalance -= MWWorld::Class::get(item).getValue(item) * count; + + updateLabels(); + } + + void TradeWindow::buyFromNpc(MWWorld::Ptr item, int count) + { + /// \todo price adjustment depending on merchantile skill + + mCurrentBalance += MWWorld::Class::get(item).getValue(item) * count; + + updateLabels(); + } +} diff --git a/apps/openmw/mwgui/tradewindow.hpp b/apps/openmw/mwgui/tradewindow.hpp new file mode 100644 index 0000000000..8da96d37e7 --- /dev/null +++ b/apps/openmw/mwgui/tradewindow.hpp @@ -0,0 +1,75 @@ +#ifndef MWGUI_TRADEWINDOW_H +#define MWGUI_TRADEWINDOW_H + +#include "container.hpp" +#include "window_base.hpp" + +#include "../mwworld/ptr.hpp" + +namespace MyGUI +{ + class Gui; + class Widget; +} + +namespace MWGui +{ + class WindowManager; +} + + +namespace MWGui +{ + class TradeWindow : public ContainerBase, public WindowBase + { + public: + TradeWindow(WindowManager& parWindowManager); + + void startTrade(MWWorld::Ptr actor); + + void sellToNpc(MWWorld::Ptr item, int count); ///< only used for adjusting the gold balance + void buyFromNpc(MWWorld::Ptr item, int count); ///< only used for adjusting the gold balance + + bool npcAcceptsItem(MWWorld::Ptr item); + + protected: + MyGUI::Button* mFilterAll; + MyGUI::Button* mFilterWeapon; + MyGUI::Button* mFilterApparel; + MyGUI::Button* mFilterMagic; + MyGUI::Button* mFilterMisc; + + MyGUI::Button* mIncreaseButton; + MyGUI::Button* mDecreaseButton; + MyGUI::TextBox* mTotalBalanceLabel; + MyGUI::TextBox* mTotalBalance; + + MyGUI::Widget* mBottomPane; + + MyGUI::Button* mMaxSaleButton; + MyGUI::Button* mCancelButton; + MyGUI::Button* mOfferButton; + MyGUI::TextBox* mPlayerGold; + MyGUI::TextBox* mMerchantGold; + + int mCurrentBalance; + + void onWindowResize(MyGUI::Window* _sender); + void onFilterChanged(MyGUI::Widget* _sender); + void onOfferButtonClicked(MyGUI::Widget* _sender); + void onCancelButtonClicked(MyGUI::Widget* _sender); + + // don't show items that the NPC has equipped in his trade-window. + virtual bool ignoreEquippedItems() { return true; } + virtual std::vector getEquippedItems(); + + virtual bool isTrading() { return true; } + virtual bool isTradeWindow() { return true; } + + virtual std::vector itemsToIgnore(); + + void updateLabels(); + }; +} + +#endif diff --git a/apps/openmw/mwgui/window_manager.cpp b/apps/openmw/mwgui/window_manager.cpp index 2200448e63..2cacf23467 100644 --- a/apps/openmw/mwgui/window_manager.cpp +++ b/apps/openmw/mwgui/window_manager.cpp @@ -1,5 +1,4 @@ #include "window_manager.hpp" -#include "layouts.hpp" #include "text_input.hpp" #include "review.hpp" #include "dialogue.hpp" @@ -7,10 +6,16 @@ #include "map_window.hpp" #include "stats_window.hpp" #include "messagebox.hpp" +#include "container.hpp" +#include "inventorywindow.hpp" #include "tooltips.hpp" #include "scrollwindow.hpp" #include "bookwindow.hpp" #include "list.hpp" +#include "hud.hpp" +#include "mainmenu.hpp" +#include "countdialog.hpp" +#include "tradewindow.hpp" #include "../mwmechanics/mechanicsmanager.hpp" #include "../mwinput/inputmanager.hpp" @@ -35,19 +40,20 @@ WindowManager::WindowManager( , hud(NULL) , map(NULL) , menu(NULL) - , stats(NULL) + , mStatsWindow(NULL) , mToolTips(NULL) , mMessageBoxManager(NULL) , console(NULL) , mJournal(NULL) + , mDialogueWindow(nullptr) , mBookWindow(NULL) , mScrollWindow(NULL) - , dialogueWindow(nullptr) + , mCountDialog(NULL) + , mTradeWindow(NULL) , mCharGen(NULL) , playerClass() , playerName() , playerRaceId() - , playerBirthSignId() , playerAttributes() , playerMajorSkills() , playerMinorSkills() @@ -71,7 +77,7 @@ WindowManager::WindowManager( // Set up the GUI system mGuiManager = new OEngine::GUI::MyGUIManager(mOgre->getWindow(), mOgre->getScene(), false, logpath); gui = mGuiManager->getGui(); - + //Register own widgets with MyGUI MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); @@ -82,22 +88,36 @@ WindowManager::WindowManager( MyGUI::FactoryManager::getInstance().registerFactory("Widget"); MyGUI::FactoryManager::getInstance().registerFactory("Widget"); + MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag); + // Get size info from the Gui object assert(gui); int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; - hud = new HUD(w,h, showFPSLevel); + MyGUI::Widget* dragAndDropWidget = gui->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; + menu = new MainMenu(w,h); map = new MapWindow(*this); - stats = new StatsWindow(*this); + mStatsWindow = new StatsWindow(*this); console = new Console(w,h, extensions); mJournal = new JournalWindow(*this); mMessageBoxManager = new MessageBoxManager(this); - dialogueWindow = new DialogueWindow(*this); + mInventoryWindow = new InventoryWindow(*this,mDragAndDrop); + mTradeWindow = new TradeWindow(*this); + mDialogueWindow = new DialogueWindow(*this); + mContainerWindow = new ContainerWindow(*this,mDragAndDrop); + hud = new HUD(w,h, showFPSLevel, mDragAndDrop); mToolTips = new ToolTips(this); mScrollWindow = new ScrollWindow(*this); mBookWindow = new BookWindow(*this); + mCountDialog = new CountDialog(*this); // The HUD is always on hud->setVisible(true); @@ -127,12 +147,17 @@ WindowManager::~WindowManager() delete hud; delete map; delete menu; - delete stats; + delete mStatsWindow; delete mJournal; - delete dialogueWindow; + delete mDialogueWindow; + delete mContainerWindow; + delete mInventoryWindow; delete mToolTips; - delete mCharGen; + delete mDragAndDrop; + delete mBookWindow; + delete mScrollWindow; + delete mTradeWindow; cleanupGarbage(); } @@ -183,12 +208,15 @@ void WindowManager::updateVisible() // Start out by hiding everything except the HUD map->setVisible(false); menu->setVisible(false); - stats->setVisible(false); + mStatsWindow->setVisible(false); console->disable(); mJournal->setVisible(false); + mDialogueWindow->setVisible(false); + mContainerWindow->setVisible(false); + mInventoryWindow->setVisible(false); mScrollWindow->setVisible(false); mBookWindow->setVisible(false); - dialogueWindow->setVisible(false); + mTradeWindow->setVisible(false); // Mouse is visible whenever we're not in game mode MyGUI::PointerManager::getInstance().setVisible(isGuiMode()); @@ -234,11 +262,23 @@ void WindowManager::updateVisible() // Show the windows we want map -> setVisible( (eff & GW_Map) != 0 ); - stats -> setVisible( (eff & GW_Stats) != 0 ); + mStatsWindow -> setVisible( (eff & GW_Stats) != 0 ); + mInventoryWindow->setVisible(true); + mInventoryWindow->openInventory(); break; } + case GM_Container: + mContainerWindow->setVisible(true); + mInventoryWindow->setVisible(true); + mInventoryWindow->openInventory(); + break; case GM_Dialogue: - dialogueWindow->open(); + mDialogueWindow->open(); + break; + case GM_Barter: + mInventoryWindow->setVisible(true); + mInventoryWindow->openInventory(); + mTradeWindow->setVisible(true); break; case GM_InterMessageBox: if(!mMessageBoxManager->isInteractiveMessageBox()) { @@ -260,7 +300,7 @@ void WindowManager::updateVisible() void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); static const char *ids[] = { @@ -290,13 +330,13 @@ void WindowManager::setValue (const std::string& id, const MWMechanics::Stat& value) { - stats->setValue(parSkill, value); + mStatsWindow->setValue(parSkill, value); playerSkillValues[parSkill] = value; } void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); hud->setValue (id, value); if (id == "HBar") { @@ -329,7 +369,7 @@ MWMechanics::DynamicStat WindowManager::getValue(const std::string& id) void WindowManager::setValue (const std::string& id, const std::string& value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); if (id=="name") playerName = value; else if (id=="race") @@ -338,46 +378,35 @@ void WindowManager::setValue (const std::string& id, const std::string& value) void WindowManager::setValue (const std::string& id, int value) { - stats->setValue (id, value); + mStatsWindow->setValue (id, value); } void WindowManager::setPlayerClass (const ESM::Class &class_) { playerClass = class_; - stats->setValue("class", playerClass.name); + mStatsWindow->setValue("class", playerClass.name); } void WindowManager::configureSkills (const SkillList& major, const SkillList& minor) { - stats->configureSkills (major, minor); + mStatsWindow->configureSkills (major, minor); playerMajorSkills = major; playerMinorSkills = minor; } -void WindowManager::setFactions (const FactionList& factions) -{ - stats->setFactions (factions); -} - -void WindowManager::setBirthSign (const std::string &signId) -{ - stats->setBirthSign (signId); - playerBirthSignId = signId; -} - void WindowManager::setReputation (int reputation) { - stats->setReputation (reputation); + mStatsWindow->setReputation (reputation); } void WindowManager::setBounty (int bounty) { - stats->setBounty (bounty); + mStatsWindow->setBounty (bounty); } void WindowManager::updateSkillArea() { - stats->updateSkillArea(); + mStatsWindow->updateSkillArea(); } void WindowManager::removeDialog(OEngine::GUI::Layout*dialog) @@ -417,11 +446,11 @@ const std::string &WindowManager::getGameSettingString(const std::string &id, co void WindowManager::onDialogueWindowBye() { - if (dialogueWindow) + if (mDialogueWindow) { //FIXME set some state and stuff? //removeDialog(dialogueWindow); - dialogueWindow->setVisible(false); + mDialogueWindow->setVisible(false); } setGuiMode(GM_Game); } @@ -430,6 +459,16 @@ void WindowManager::onFrame (float frameDuration) { mMessageBoxManager->onFrame(frameDuration); mToolTips->onFrame(frameDuration); + + if (mDragAndDrop->mIsOnDragAndDrop) + { + assert(mDragAndDrop->mDraggedWidget); + mDragAndDrop->mDraggedWidget->setPosition(MyGUI::InputManager::getInstance().getMousePosition()); + } + + mInventoryWindow->onFrame(); + + mStatsWindow->onFrame(); } const ESMS::ESMStore& WindowManager::getStore() const @@ -516,6 +555,11 @@ void WindowManager::setFocusObject(const MWWorld::Ptr& focus) mToolTips->setFocusObject(focus); } +void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y) +{ + mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y); +} + void WindowManager::toggleFullHelp() { mToolTips->toggleFullHelp(); @@ -525,3 +569,31 @@ bool WindowManager::getFullHelp() const { return mToolTips->getFullHelp(); } + +void WindowManager::setWeaponVisibility(bool visible) +{ + hud->weapBox->setVisible(visible); +} + +void WindowManager::setSpellVisibility(bool visible) +{ + hud->spellBox->setVisible(visible); +} + +void WindowManager::setMouseVisible(bool visible) +{ + MyGUI::PointerManager::getInstance().setVisible(visible); +} + +void WindowManager::setDragDrop(bool dragDrop) +{ + mToolTips->setEnabled(!dragDrop); + MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); +} + +void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result) +{ + const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().gameSettings.search(_tag); + if (setting && setting->type == ESM::VT_String) + _result = setting->str; +} diff --git a/apps/openmw/mwgui/window_manager.hpp b/apps/openmw/mwgui/window_manager.hpp index b84c74441b..22fe973a59 100644 --- a/apps/openmw/mwgui/window_manager.hpp +++ b/apps/openmw/mwgui/window_manager.hpp @@ -14,11 +14,15 @@ #include #include +#include "MyGUI_UString.h" + #include #include #include + #include "../mwmechanics/stat.hpp" #include "../mwworld/ptr.hpp" + #include "mode.hpp" namespace MyGUI @@ -61,14 +65,18 @@ namespace MWGui class Console; class JournalWindow; class CharacterCreation; + class ContainerWindow; + class DragAndDrop; + class InventoryWindow; class ToolTips; class ScrollWindow; class BookWindow; - class TextInputDialog; class InfoBoxDialog; class DialogueWindow; class MessageBoxManager; + class CountDialog; + class TradeWindow; struct ClassPoint { @@ -125,10 +133,13 @@ namespace MWGui updateVisible(); } - MWGui::DialogueWindow* getDialogueWindow() {return dialogueWindow;} - + MWGui::DialogueWindow* getDialogueWindow() {return mDialogueWindow;} + MWGui::ContainerWindow* getContainerWindow() {return mContainerWindow;} + MWGui::InventoryWindow* getInventoryWindow() {return mInventoryWindow;} MWGui::BookWindow* getBookWindow() {return mBookWindow;} MWGui::ScrollWindow* getScrollWindow() {return mScrollWindow;} + MWGui::CountDialog* getCountDialog() {return mCountDialog;} + MWGui::TradeWindow* getTradeWindow() {return mTradeWindow;} MyGUI::Gui* getGui() const { return gui; } @@ -150,8 +161,6 @@ namespace MWGui void setPlayerClass (const ESM::Class &class_); ///< set current class of player void configureSkills (const SkillList& major, const SkillList& minor); ///< configure skill groups, each set contains the skill ID for that group. - void setFactions (const FactionList& factions); ///< set faction and rank to display on stat window, use an empty vector to disable - void setBirthSign (const std::string &signId); ///< set birth sign to display on stat window, use an empty string to disable. void setReputation (int reputation); ///< set the current reputation value void setBounty (int bounty); ///< set the current bounty value void updateSkillArea(); ///< update display of skills, factions, birth sign, reputation and bounty @@ -161,6 +170,10 @@ namespace MWGui void setPlayerDir(const float x, const float y); ///< set player view direction in map space void setFocusObject(const MWWorld::Ptr& focus); + void setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y); + + void setMouseVisible(bool visible); + void setDragDrop(bool dragDrop); void toggleFogOfWar(); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) @@ -176,6 +189,8 @@ namespace MWGui void setHMSVisibility(bool visible); // sets the visibility of the hud minimap void setMinimapVisibility(bool visible); + void setWeaponVisibility(bool visible); + void setSpellVisibility(bool visible); template void removeDialog(T*& dialog); ///< Casts to OEngine::GUI::Layout and calls removeDialog, then resets pointer to nullptr. @@ -203,13 +218,18 @@ namespace MWGui MapWindow *map; MainMenu *menu; ToolTips *mToolTips; - StatsWindow *stats; + StatsWindow *mStatsWindow; MessageBoxManager *mMessageBoxManager; Console *console; JournalWindow* mJournal; - DialogueWindow *dialogueWindow; + DialogueWindow *mDialogueWindow; + ContainerWindow *mContainerWindow; + DragAndDrop* mDragAndDrop; + InventoryWindow *mInventoryWindow; ScrollWindow* mScrollWindow; BookWindow* mBookWindow; + CountDialog* mCountDialog; + TradeWindow* mTradeWindow; CharacterCreation* mCharGen; @@ -217,7 +237,6 @@ namespace MWGui ESM::Class playerClass; std::string playerName; std::string playerRaceId; - std::string playerBirthSignId; std::map > playerAttributes; SkillList playerMajorSkills, playerMinorSkills; std::map > playerSkillValues; @@ -252,6 +271,12 @@ namespace MWGui size_t mBatchCount; void onDialogueWindowBye(); + + /** + * Called when MyGUI tries to retrieve a tag. This usually corresponds to a GMST string, + * so this method will retrieve the GMST with the name \a _tag and place the result in \a _result + */ + void onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result); }; template diff --git a/apps/openmw/mwinput/inputmanager.cpp b/apps/openmw/mwinput/inputmanager.cpp index 9026cdf640..8f8f1e1ee2 100644 --- a/apps/openmw/mwinput/inputmanager.cpp +++ b/apps/openmw/mwinput/inputmanager.cpp @@ -60,7 +60,7 @@ namespace MWInput A_CycleWeaponRight, A_ToggleSneak, //Toggles Sneak, add Push-Sneak later A_ToggleWalk, //Toggle Walking/Running - A_Crouch, + A_Crouch, A_QuickSave, A_QuickLoad, @@ -88,6 +88,8 @@ namespace MWInput MWGui::WindowManager &windows; OMW::Engine& mEngine; + bool mDragDrop; + /* InputImpl Methods */ @@ -143,6 +145,9 @@ namespace MWInput { using namespace MWGui; + if (mDragDrop) + return; + GuiMode mode = windows.getMode(); // Toggle between game mode and inventory mode @@ -159,6 +164,9 @@ namespace MWInput { using namespace MWGui; + if (mDragDrop) + return; + GuiMode mode = windows.getMode(); // Switch to console mode no matter what mode we are currently @@ -219,7 +227,8 @@ namespace MWInput poller(input), player(_player), windows(_windows), - mEngine (engine) + mEngine (engine), + mDragDrop(false) { using namespace OEngine::Input; using namespace OEngine::Render; @@ -314,9 +323,14 @@ namespace MWInput poller.bind(A_MoveRight, KC_D); poller.bind(A_MoveForward, KC_W); poller.bind(A_MoveBackward, KC_S); - - poller.bind(A_Jump, KC_E); - poller.bind(A_Crouch, KC_LCONTROL); + + poller.bind(A_Jump, KC_E); + poller.bind(A_Crouch, KC_LCONTROL); + } + + void setDragDrop(bool dragDrop) + { + mDragDrop = dragDrop; } //NOTE: Used to check for movement keys @@ -364,7 +378,7 @@ namespace MWInput else player.setForwardBackward (0); - if (poller.isDown(A_Jump)) + if (poller.isDown(A_Jump)) player.setUpDown (1); else if (poller.isDown(A_Crouch)) player.setUpDown (-1); @@ -426,4 +440,9 @@ namespace MWInput { impl->update(); } + + void MWInputManager::setDragDrop(bool dragDrop) + { + impl->setDragDrop(dragDrop); + } } diff --git a/apps/openmw/mwinput/inputmanager.hpp b/apps/openmw/mwinput/inputmanager.hpp index 721c77d9fd..158d05f0ee 100644 --- a/apps/openmw/mwinput/inputmanager.hpp +++ b/apps/openmw/mwinput/inputmanager.hpp @@ -50,6 +50,8 @@ namespace MWInput void update(); + void setDragDrop(bool dragDrop); + void setGuiMode(MWGui::GuiMode mode); }; } diff --git a/apps/openmw/mwmechanics/npcstats.hpp b/apps/openmw/mwmechanics/npcstats.hpp index feac5d4d3c..972863b728 100644 --- a/apps/openmw/mwmechanics/npcstats.hpp +++ b/apps/openmw/mwmechanics/npcstats.hpp @@ -20,6 +20,7 @@ namespace MWMechanics { // NPCs other than the player can only have one faction. But for the sake of consistency // we use the same data structure for the PC and the NPCs. + /// \note the faction key must be in lowercase std::map mFactionRank; Stat mSkill[27]; diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 27c3f818e8..b9efcd3f5d 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -219,7 +219,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f info.type = LT_Normal; // random starting phase for the animation - info.time = Ogre::Math::RangeRandom(0, 2 * M_PI); + info.time = Ogre::Math::RangeRandom(0, 2 * Ogre::Math::PI); // adjust the lights depending if we're in an interior or exterior cell // quadratic means the light intensity falls off quite fast, resulting in a @@ -367,7 +367,7 @@ void Objects::update(const float dt) // Light animation (pulse & flicker) it->time += dt; - const float phase = std::fmod(static_cast (it->time), (32 * 2 * M_PI)) * 20; + const float phase = std::fmod(static_cast (it->time), static_cast(32 * 2 * Ogre::Math::PI)) * 20; float pulseConstant; // These formulas are just guesswork, but they work pretty well diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 18d512ac8d..d49a961012 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -521,4 +521,43 @@ void RenderingManager::switchToExterior() mRendering.getScene()->setCameraRelativeRendering(true); } +Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) +{ + Ogre::Matrix4 mat = mRendering.getCamera()->getViewMatrix(); + + const Ogre::Vector3* corners = bounds.getAllCorners(); + + float min_x = 1.0f, max_x = 0.0f, min_y = 1.0f, max_y = 0.0f; + + // expand the screen-space bounding-box so that it completely encloses + // the object's AABB + for (int i=0; i<8; i++) + { + Ogre::Vector3 corner = corners[i]; + + // multiply the AABB corner vertex by the view matrix to + // get a camera-space vertex + corner = mat * corner; + + // make 2D relative/normalized coords from the view-space vertex + // by dividing out the Z (depth) factor -- this is an approximation + float x = corner.x / corner.z + 0.5; + float y = corner.y / corner.z + 0.5; + + if (x < min_x) + min_x = x; + + if (x > max_x) + max_x = x; + + if (y < min_y) + min_y = y; + + if (y > max_y) + max_y = y; + } + + return Vector4(min_x, min_y, max_x, max_y); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0d11b3d57d..8b457997de 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -151,6 +151,10 @@ class RenderingManager: private RenderingInterface { ///< Skip the animation for the given MW-reference for one frame. Calls to this function for /// references that are currently not in the rendered scene should be ignored. + Ogre::Vector4 boundingBoxToScreen(Ogre::AxisAlignedBox bounds); + ///< transform the specified bounding box (in world coordinates) into screen coordinates. + /// @return packed vector4 (min_x, min_y, max_x, max_y) + private: void setAmbientMode(); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c81f23f548..840b94e41e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -155,10 +155,10 @@ void Water::changeCell(const ESM::Cell* cell) { mTop = cell->water; + setHeight(mTop); + if(!(cell->data.flags & cell->Interior)) mWaterNode->setPosition(getSceneNodeCoordinates(cell->data.gridX, cell->data.gridY)); - else - setHeight(mTop); } void Water::setHeight(const float height) diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index cad52e5930..d235192817 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1,6 +1,8 @@ #include "statsextensions.hpp" +#include + #include #include @@ -362,6 +364,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } + boost::algorithm::to_lower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -390,6 +393,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } + boost::algorithm::to_lower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -422,6 +426,7 @@ namespace MWScript factionID = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); } + boost::algorithm::to_lower(factionID); if(factionID != "") { MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); @@ -459,6 +464,7 @@ namespace MWScript factionID = MWWorld::Class::get(ptr).getNpcStats(ptr).mFactionRank.begin()->first; } } + boost::algorithm::to_lower(factionID); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); if(factionID!="") { diff --git a/apps/openmw/mwworld/actionequip.cpp b/apps/openmw/mwworld/actionequip.cpp new file mode 100644 index 0000000000..f3bb256fd8 --- /dev/null +++ b/apps/openmw/mwworld/actionequip.cpp @@ -0,0 +1,54 @@ +#include "actionequip.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" +#include "../mwworld/inventorystore.hpp" +#include "../mwworld/player.hpp" + +namespace MWWorld +{ + ActionEquip::ActionEquip (const MWWorld::Ptr& object) : mObject (object) + { + } + + void ActionEquip::execute () + { + MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayer().getPlayer(); + MWWorld::InventoryStore& invStore = static_cast(MWWorld::Class::get(player).getContainerStore(player)); + + // slots that this item can be equipped in + std::pair, bool> slots = MWWorld::Class::get(mObject).getEquipmentSlots(mObject); + + // retrieve ContainerStoreIterator to the item + MWWorld::ContainerStoreIterator it = invStore.begin(); + for (; it != invStore.end(); ++it) + { + if (*it == mObject) + { + break; + } + } + + assert(it != invStore.end()); + + // equip the item in the first free slot + for (std::vector::const_iterator slot=slots.first.begin(); + slot!=slots.first.end(); ++slot) + { + // if all slots are occupied, replace the last slot + if (slot == --slots.first.end()) + { + invStore.equip(*slot, it); + break; + } + + if (invStore.getSlot(*slot) == invStore.end()) + { + // slot is not occupied + invStore.equip(*slot, it); + break; + } + } + } +} + diff --git a/apps/openmw/mwworld/actionequip.hpp b/apps/openmw/mwworld/actionequip.hpp new file mode 100644 index 0000000000..6cf3640f8b --- /dev/null +++ b/apps/openmw/mwworld/actionequip.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_MWWORLD_ACTIONEQUIP_H +#define GAME_MWWORLD_ACTIONEQUIP_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionEquip : public Action + { + Ptr mObject; + + public: + /// @param item to equip + ActionEquip (const Ptr& object); + + virtual void execute (); + }; +} + +#endif diff --git a/apps/openmw/mwworld/actionopen.cpp b/apps/openmw/mwworld/actionopen.cpp new file mode 100644 index 0000000000..e450585e63 --- /dev/null +++ b/apps/openmw/mwworld/actionopen.cpp @@ -0,0 +1,22 @@ +#include "actionopen.hpp" + +#include "../mwbase/environment.hpp" +#include "class.hpp" +#include "world.hpp" +#include "containerstore.hpp" +#include "../mwclass/container.hpp" +#include "../mwgui/window_manager.hpp" +#include "../mwgui/container.hpp" + +namespace MWWorld +{ + ActionOpen::ActionOpen (const MWWorld::Ptr& container) : mContainer (container) { + mContainer = container; + } + + void ActionOpen::execute () + { + MWBase::Environment::get().getWindowManager()->setGuiMode(MWGui::GM_Container); + MWBase::Environment::get().getWindowManager()->getContainerWindow()->open(mContainer); + } +} diff --git a/apps/openmw/mwworld/actionopen.hpp b/apps/openmw/mwworld/actionopen.hpp new file mode 100644 index 0000000000..eff26c78c1 --- /dev/null +++ b/apps/openmw/mwworld/actionopen.hpp @@ -0,0 +1,22 @@ + +#ifndef GAME_MWWORLD_ACTIONOPEN_H +#define GAME_MWWORLD_ACTIONOPEN_H + +#include "action.hpp" +#include "ptr.hpp" + + +namespace MWWorld +{ + class ActionOpen : public Action + { + Ptr mContainer; + + public: + ActionOpen (const Ptr& container); + ///< \param The Container the Player has activated. + virtual void execute (); + }; +} + +#endif // ACTIONOPEN_H diff --git a/apps/openmw/mwworld/actiontake.cpp b/apps/openmw/mwworld/actiontake.cpp index b1e2e1fc3d..384cb3ffe1 100644 --- a/apps/openmw/mwworld/actiontake.cpp +++ b/apps/openmw/mwworld/actiontake.cpp @@ -18,7 +18,8 @@ namespace MWWorld MWWorld::Class::get (player).getContainerStore (player).add (mObject); - // remove from world - MWBase::Environment::get().getWorld()->deleteObject (mObject); + // remove from world, if the item is currently in the world (it could also be in a container) + if (mObject.isInCell()) + MWBase::Environment::get().getWorld()->deleteObject (mObject); } } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index f1c50c29a7..6a67652539 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -142,7 +142,7 @@ namespace MWWorld throw std::logic_error ("value not supported by this class"); } - float Class::getCapactiy (const MWWorld::Ptr& ptr) const + float Class::getCapacity (const MWWorld::Ptr& ptr) const { throw std::runtime_error ("capacity not supported by this class"); } @@ -182,6 +182,12 @@ namespace MWWorld throw std::runtime_error ("class does not have an down sound"); } + + std::string Class::getInventoryIcon (const MWWorld::Ptr& ptr) const + { + throw std::runtime_error ("class does not have any inventory icon"); + } + MWGui::ToolTipInfo Class::getToolTipInfo (const Ptr& ptr) const { throw std::runtime_error ("class does not have a tool tip"); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0fc12bfe2b..0ed0b0e0d1 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -164,7 +164,7 @@ namespace MWWorld ///< Return trade value of the object. Throws an exception, if the object can't be traded. /// (default implementation: throws an exception) - virtual float getCapactiy (const MWWorld::Ptr& ptr) const; + virtual float getCapacity (const MWWorld::Ptr& ptr) const; ///< Return total weight that fits into the object. Throws an exception, if the object can't /// hold other objects. /// (default implementation: throws an exception) @@ -190,6 +190,9 @@ namespace MWWorld ///< Return the down sound ID of \a ptr or throw an exception, if class does not support ID retrieval /// (default implementation: throw an exception) + virtual std::string getInventoryIcon (const MWWorld::Ptr& ptr) const; + ///< Return name of inventory icon. + virtual std::string getEnchantment (const MWWorld::Ptr& ptr) const; ///< @return the enchantment ID if the object is enchanted, otherwise an empty string /// (default implementation: return empty string) diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index ee1b620cd7..b669508b25 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -5,8 +5,13 @@ #include #include +#include + #include +#include "../mwbase/environment.hpp" +#include "../mwworld/world.hpp" + #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" @@ -29,6 +34,12 @@ namespace return sum; } + + bool compare_string_ci(std::string str1, std::string str2) + { + boost::algorithm::to_lower(str1); + return str1 == str2; + } } MWWorld::ContainerStore::ContainerStore() : mStateId (0), mCachedWeight (0), mWeightUpToDate (false) {} @@ -58,10 +69,41 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) return false; } -void MWWorld::ContainerStore::add (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) { int type = getType(ptr); + // gold needs special handling: when it is inserted into a container, the base object automatically becomes Gold_001 + // this ensures that gold piles of different sizes stack with each other (also, several scripts rely on Gold_001 for detecting player gold) + if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + ESMS::LiveCellRef *gold = + ptr.get(); + + if (compare_string_ci(gold->ref.refID, "gold_001") + || compare_string_ci(gold->ref.refID, "gold_005") + || compare_string_ci(gold->ref.refID, "gold_010") + || compare_string_ci(gold->ref.refID, "gold_025") + || compare_string_ci(gold->ref.refID, "gold_100")) + { + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), "Gold_001"); + + int count = (ptr.getRefData().getCount() == 1) ? gold->base->data.value : ptr.getRefData().getCount(); + ref.getPtr().getRefData().setCount(count); + for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) + { + if (compare_string_ci((*iter).get()->ref.refID, "gold_001")) + { + (*iter).getRefData().setCount( (*iter).getRefData().getCount() + count); + flagAsModified(); + return iter; + } + } + + return addImpl(ref.getPtr()); + } + } + // determine whether to stack or not for (MWWorld::ContainerStoreIterator iter (begin(type)); iter!=end(); ++iter) { @@ -71,33 +113,36 @@ void MWWorld::ContainerStore::add (const Ptr& ptr) iter->getRefData().setCount( iter->getRefData().getCount() + ptr.getRefData().getCount() ); flagAsModified(); - return; + return iter; } } // if we got here, this means no stacking - addImpl(ptr); + return addImpl(ptr); } -void MWWorld::ContainerStore::addImpl (const Ptr& ptr) +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImpl (const Ptr& ptr) { + ContainerStoreIterator it = begin(); + switch (getType(ptr)) { - case Type_Potion: potions.list.push_back (*ptr.get()); break; - case Type_Apparatus: appas.list.push_back (*ptr.get()); break; - case Type_Armor: armors.list.push_back (*ptr.get()); break; - case Type_Book: books.list.push_back (*ptr.get()); break; - case Type_Clothing: clothes.list.push_back (*ptr.get()); break; - case Type_Ingredient: ingreds.list.push_back (*ptr.get()); break; - case Type_Light: lights.list.push_back (*ptr.get()); break; - case Type_Lockpick: lockpicks.list.push_back (*ptr.get()); break; - case Type_Miscellaneous: miscItems.list.push_back (*ptr.get()); break; - case Type_Probe: probes.list.push_back (*ptr.get()); break; - case Type_Repair: repairs.list.push_back (*ptr.get()); break; - case Type_Weapon: weapons.list.push_back (*ptr.get()); break; + case Type_Potion: potions.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --potions.list.end()); break; + case Type_Apparatus: appas.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --appas.list.end()); break; + case Type_Armor: armors.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --armors.list.end()); break; + case Type_Book: books.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --books.list.end()); break; + case Type_Clothing: clothes.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --clothes.list.end()); break; + case Type_Ingredient: ingreds.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --ingreds.list.end()); break; + case Type_Light: lights.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lights.list.end()); break; + case Type_Lockpick: lockpicks.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --lockpicks.list.end()); break; + case Type_Miscellaneous: miscItems.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --miscItems.list.end()); break; + case Type_Probe: probes.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --probes.list.end()); break; + case Type_Repair: repairs.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --repairs.list.end()); break; + case Type_Weapon: weapons.list.push_back (*ptr.get()); it = ContainerStoreIterator(this, --weapons.list.end()); break; } flagAsModified(); + return it; } void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS::ESMStore& store) @@ -113,7 +158,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const ESMS: continue; } - ref.getPtr().getRefData().setCount (iter->count); + ref.getPtr().getRefData().setCount (std::abs(iter->count)); /// \todo implement item restocking (indicated by negative count) add (ref.getPtr()); } @@ -228,8 +273,38 @@ MWWorld::ContainerStoreIterator::ContainerStoreIterator (int mask, ContainerStor : mType (0), mMask (mask), mContainer (container) { nextType(); + + if (mType==-1 || (**this).getRefData().getCount()) + return; + + ++*this; } +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Potion), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mPotion(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Apparatus), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mApparatus(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Armor), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mArmor(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Book), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mBook(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Clothing), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mClothing(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Ingredient), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mIngredient(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Light), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLight(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Lockpick), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mLockpick(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Miscellaneous), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mMiscellaneous(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Probe), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mProbe(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Repair), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mRepair(iterator){} +MWWorld::ContainerStoreIterator::ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator iterator) + : mType(MWWorld::ContainerStore::Type_Weapon), mMask(MWWorld::ContainerStore::Type_All), mContainer(container), mWeapon(iterator){} + void MWWorld::ContainerStoreIterator::incType() { if (mType==0) @@ -249,7 +324,7 @@ void MWWorld::ContainerStoreIterator::nextType() { incType(); - if (mType & mMask) + if ((mType & mMask) && mType>0) if (resetIterator()) break; } diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index f677e0dcbb..15b553f9dd 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -66,16 +66,18 @@ namespace MWWorld ContainerStoreIterator end(); - void add (const Ptr& ptr); + ContainerStoreIterator add (const Ptr& ptr); ///< Add the item pointed to by \a ptr to this container. (Stacks automatically if needed) /// /// \note The item pointed to is not required to exist beyond this function call. /// /// \attention Do not add items to an existing stack by increasing the count instead of /// calling this function! + /// + /// @return if stacking happened, return iterator to the item that was stacked against, otherwise iterator to the newly inserted item. protected: - void addImpl (const Ptr& ptr); + ContainerStoreIterator addImpl (const Ptr& ptr); ///< Add the item to this container (no stacking) virtual bool stacks (const Ptr& ptr1, const Ptr& ptr2); @@ -141,6 +143,20 @@ namespace MWWorld ContainerStoreIterator (int mask, ContainerStore *container); ///< Begin-iterator + // construct iterator using a CellRefList iterator + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + ContainerStoreIterator (ContainerStore *container, ESMS::CellRefList::List::iterator); + void incType(); void nextType(); diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index fb13e37c6a..808c712a07 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -80,7 +80,7 @@ namespace MWWorld Ray centerRay = mRender.getCamera()->getCameraToViewportRay( mRender.getViewport()->getWidth()/2, mRender.getViewport()->getHeight()/2); - btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); + btVector3 result(centerRay.getPoint(500*extent).x,-centerRay.getPoint(500*extent).z,centerRay.getPoint(500*extent).y); /// \todo make this distance (ray length) configurable return result; } @@ -95,6 +95,29 @@ namespace MWWorld return !(result.first == ""); } + std::pair PhysicsSystem::castRay(float mouseX, float mouseY) + { + Ogre::Ray ray = mRender.getCamera()->getCameraToViewportRay( + mouseX, + mouseY); + Ogre::Vector3 from = ray.getOrigin(); + Ogre::Vector3 to = ray.getPoint(200); /// \todo make this distance (ray length) configurable + + btVector3 _from, _to; + // OGRE to MW coordinates + _from = btVector3(from.x, -from.z, from.y); + _to = btVector3(to.x, -to.z, to.y); + + std::pair result = mEngine->rayTest(_from, _to); + + if (result.first == "") + return std::make_pair(false, Ogre::Vector3()); + else + { + return std::make_pair(true, ray.getPoint(200*result.second)); /// \todo make this distance (ray length) configurable + } + } + void PhysicsSystem::doPhysics(float dt, const std::vector >& actors) { //set the DebugRenderingMode. To disable it,set it to 0 diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 1af6bcca2f..9b03d2124f 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -53,6 +53,9 @@ namespace MWWorld // cast ray, return true if it hit something bool castRay(const Ogre::Vector3& from, const Ogre::Vector3& to); + std::pair castRay(float mouseX, float mouseY); + ///< cast ray from the mouse, return true if it hit something and the first result (in OGRE coordinates) + void insertObjectPhysics(const MWWorld::Ptr& ptr, std::string model); void insertActorPhysics(const MWWorld::Ptr&, std::string model); diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index d6e485f419..4cf3e98da4 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -77,6 +77,11 @@ namespace MWWorld return mCell; } + bool isInCell() const + { + return (mCell != 0); + } + void setContainerStore (ContainerStore *store); ///< Must not be called on references that are in a cell. diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index e4236b2f7f..94f0c69a95 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -9,45 +9,49 @@ #include "../mwgui/window_manager.hpp" +#include "../mwworld/world.hpp" /// FIXME +#include "../mwworld/manualref.hpp" /// FIXME + #include "ptr.hpp" #include "player.hpp" #include "class.hpp" #include "cellfunctors.hpp" -namespace { - -template -void insertCellRefList(MWRender::RenderingManager& rendering, - T& cellRefList, ESMS::CellStore &cell, MWWorld::PhysicsSystem& physics) +namespace { - if (!cellRefList.list.empty()) + + template + void insertCellRefList(MWRender::RenderingManager& rendering, + T& cellRefList, ESMS::CellStore &cell, MWWorld::PhysicsSystem& physics) { - const MWWorld::Class& class_ = - MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); - - for (typename T::List::iterator it = cellRefList.list.begin(); - it != cellRefList.list.end(); it++) + if (!cellRefList.list.empty()) { - if (it->mData.getCount() || it->mData.isEnabled()) - { - MWWorld::Ptr ptr (&*it, &cell); + const MWWorld::Class& class_ = + MWWorld::Class::get (MWWorld::Ptr (&*cellRefList.list.begin(), &cell)); - try + for (typename T::List::iterator it = cellRefList.list.begin(); + it != cellRefList.list.end(); it++) + { + if (it->mData.getCount() || it->mData.isEnabled()) { - rendering.addObject(ptr); - class_.insertObject(ptr, physics); - class_.enable (ptr); - } - catch (const std::exception& e) - { - std::string error ("error during rendering: "); - std::cerr << error + e.what() << std::endl; + MWWorld::Ptr ptr (&*it, &cell); + + try + { + rendering.addObject(ptr); + class_.insertObject(ptr, physics); + class_.enable (ptr); + } + catch (const std::exception& e) + { + std::string error ("error during rendering: "); + std::cerr << error + e.what() << std::endl; + } } } } } -} } @@ -306,30 +310,157 @@ namespace MWWorld mCellChanged = false; } -void Scene::insertCell(ESMS::CellStore &cell) -{ - // Loop through all references in the cell - insertCellRefList(mRendering, cell.activators, cell, *mPhysics); - insertCellRefList(mRendering, cell.potions, cell, *mPhysics); - insertCellRefList(mRendering, cell.appas, cell, *mPhysics); - insertCellRefList(mRendering, cell.armors, cell, *mPhysics); - insertCellRefList(mRendering, cell.books, cell, *mPhysics); - insertCellRefList(mRendering, cell.clothes, cell, *mPhysics); - insertCellRefList(mRendering, cell.containers, cell, *mPhysics); - insertCellRefList(mRendering, cell.creatures, cell, *mPhysics); - insertCellRefList(mRendering, cell.doors, cell, *mPhysics); - insertCellRefList(mRendering, cell.ingreds, cell, *mPhysics); - insertCellRefList(mRendering, cell.creatureLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.itemLists, cell, *mPhysics); - insertCellRefList(mRendering, cell.lights, cell, *mPhysics); - insertCellRefList(mRendering, cell.lockpicks, cell, *mPhysics); - insertCellRefList(mRendering, cell.miscItems, cell, *mPhysics); - insertCellRefList(mRendering, cell.npcs, cell, *mPhysics); - insertCellRefList(mRendering, cell.probes, cell, *mPhysics); - insertCellRefList(mRendering, cell.repairs, cell, *mPhysics); - insertCellRefList(mRendering, cell.statics, cell, *mPhysics); - insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); -} + void Scene::insertCell(ESMS::CellStore &cell) + { + // Loop through all references in the cell + insertCellRefList(mRendering, cell.activators, cell, *mPhysics); + insertCellRefList(mRendering, cell.potions, cell, *mPhysics); + insertCellRefList(mRendering, cell.appas, cell, *mPhysics); + insertCellRefList(mRendering, cell.armors, cell, *mPhysics); + insertCellRefList(mRendering, cell.books, cell, *mPhysics); + insertCellRefList(mRendering, cell.clothes, cell, *mPhysics); + insertCellRefList(mRendering, cell.containers, cell, *mPhysics); + insertCellRefList(mRendering, cell.creatures, cell, *mPhysics); + insertCellRefList(mRendering, cell.doors, cell, *mPhysics); + insertCellRefList(mRendering, cell.ingreds, cell, *mPhysics); + insertCellRefList(mRendering, cell.creatureLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.itemLists, cell, *mPhysics); + insertCellRefList(mRendering, cell.lights, cell, *mPhysics); + insertCellRefList(mRendering, cell.lockpicks, cell, *mPhysics); + insertCellRefList(mRendering, cell.miscItems, cell, *mPhysics); + insertCellRefList(mRendering, cell.npcs, cell, *mPhysics); + insertCellRefList(mRendering, cell.probes, cell, *mPhysics); + insertCellRefList(mRendering, cell.repairs, cell, *mPhysics); + insertCellRefList(mRendering, cell.statics, cell, *mPhysics); + insertCellRefList(mRendering, cell.weapons, cell, *mPhysics); + } + /// \todo this whole code needs major clean up, and doesn't belong in this class. + void Scene::insertObject(MWWorld::Ptr ptr, Ptr::CellStore* cell) + { + std::string type = ptr.getTypeName(); + + MWWorld::Ptr newPtr; + + // insert into the correct CellRefList + if (type == typeid(ESM::Potion).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->potions.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->potions.list.back(), cell); + } + else if (type == typeid(ESM::Apparatus).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->appas.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->appas.list.back(), cell); + } + else if (type == typeid(ESM::Armor).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->armors.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->armors.list.back(), cell); + } + else if (type == typeid(ESM::Book).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->books.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->books.list.back(), cell); + } + else if (type == typeid(ESM::Clothing).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->clothes.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->clothes.list.back(), cell); + } + else if (type == typeid(ESM::Ingredient).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->ingreds.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->ingreds.list.back(), cell); + } + else if (type == typeid(ESM::Light).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->lights.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->lights.list.back(), cell); + } + else if (type == typeid(ESM::Tool).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->lockpicks.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->lockpicks.list.back(), cell); + } + else if (type == typeid(ESM::Repair).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->repairs.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->repairs.list.back(), cell); + } + else if (type == typeid(ESM::Probe).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->probes.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->probes.list.back(), cell); + } + else if (type == typeid(ESM::Weapon).name()) + { + ESMS::LiveCellRef* ref = ptr.get(); + cell->weapons.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->weapons.list.back(), cell); + } + else if (type == typeid(ESM::Miscellaneous).name()) + { + + // if this is gold, we need to fetch the correct mesh depending on the amount of gold. + if (MWWorld::Class::get(ptr).getName(ptr) == MWBase::Environment::get().getWorld()->getStore().gameSettings.search("sGold")->str) + { + int goldAmount = ptr.getRefData().getCount(); + + std::string base = "Gold_001"; + if (goldAmount >= 100) + base = "Gold_100"; + else if (goldAmount >= 25) + base = "Gold_025"; + else if (goldAmount >= 10) + base = "Gold_010"; + else if (goldAmount >= 5) + base = "Gold_005"; + + MWWorld::ManualRef newRef (MWBase::Environment::get().getWorld()->getStore(), base); + + ESMS::LiveCellRef* ref = newRef.getPtr().get(); + + cell->miscItems.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); + + ESM::Position& p = newPtr.getRefData().getPosition(); + p.pos[0] = ptr.getRefData().getPosition().pos[0]; + p.pos[1] = ptr.getRefData().getPosition().pos[1]; + p.pos[2] = ptr.getRefData().getPosition().pos[2]; + } + else + { + ESMS::LiveCellRef* ref = ptr.get(); + + cell->miscItems.list.push_back( *ref ); + newPtr = MWWorld::Ptr(&cell->miscItems.list.back(), cell); + } + } + else + throw std::runtime_error("Trying to insert object of unhandled type"); + + + + newPtr.getRefData().setCount(ptr.getRefData().getCount()); + ptr.getRefData().setCount(0); + newPtr.getRefData().enable(); + + mRendering.addObject(newPtr); + MWWorld::Class::get(newPtr).insertObject(newPtr, *mPhysics); + MWWorld::Class::get(newPtr).enable(newPtr); + + } + } diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index 1a9f2f271a..857ee50d1e 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -100,6 +100,10 @@ namespace MWWorld void insertCell(ESMS::CellStore &cell); + /// this method is only meant for dropping objects into the gameworld from a container + /// and thus only handles object types that can be placed in a container + void insertObject(MWWorld::Ptr object, Ptr::CellStore* cell); + void update (float duration); }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index fbbeef154c..c2926c1a3f 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -21,7 +21,7 @@ #include "class.hpp" #include "player.hpp" #include "weather.hpp" - +#include "manualref.hpp" #include "refdata.hpp" #include "globals.hpp" #include "cellfunctors.hpp" @@ -779,7 +779,24 @@ namespace MWWorld // inform the GUI about focused object try { - MWBase::Environment::get().getWindowManager()->setFocusObject(getPtrViaHandle(mFacedHandle)); + MWWorld::Ptr object = getPtrViaHandle(mFacedHandle); + MWBase::Environment::get().getWindowManager()->setFocusObject(object); + + // retrieve object dimensions so we know where to place the floating label + Ogre::SceneNode* node = object.getRefData().getBaseNode(); + Ogre::AxisAlignedBox bounds; + int i; + for (i=0; inumAttachedObjects(); ++i) + { + Ogre::MovableObject* ob = node->getAttachedObject(i); + bounds.merge(ob->getWorldBoundingBox()); + } + if (bounds.isFinite()) + { + Vector4 screenCoords = mRendering->boundingBoxToScreen(bounds); + MWBase::Environment::get().getWindowManager()->setFocusObjectScreenCoords( + screenCoords[0], screenCoords[1], screenCoords[2], screenCoords[3]); + } } catch (std::runtime_error&) { @@ -959,4 +976,57 @@ namespace MWWorld mRendering->toggleWater(); } + bool World::placeObject(MWWorld::Ptr object, float cursorX, float cursorY) + { + std::pair result = mPhysics->castRay(cursorX, cursorY); + + if (!result.first) + return false; + + MWWorld::Ptr::CellStore* cell; + if (isCellExterior()) + { + int cellX, cellY; + positionToIndex(result.second[0], -result.second[2], cellX, cellY); + cell = mCells.getExterior(cellX, cellY); + } + else + cell = getPlayer().getPlayer().getCell(); + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = result.second[0]; + pos.pos[1] = -result.second[2]; + pos.pos[2] = result.second[1]; + + mWorldScene->insertObject(object, cell); + + /// \todo retrieve the bounds of the object and translate it accordingly + + return true; + } + + bool World::canPlaceObject(float cursorX, float cursorY) + { + std::pair result = mPhysics->castRay(cursorX, cursorY); + + /// \todo also check if the wanted position is on a flat surface, and not e.g. against a vertical wall! + + if (!result.first) + return false; + return true; + } + + void World::dropObjectOnGround(MWWorld::Ptr object) + { + MWWorld::Ptr::CellStore* cell = getPlayer().getPlayer().getCell(); + + float* playerPos = getPlayer().getPlayer().getRefData().getPosition().pos; + + ESM::Position& pos = object.getRefData().getPosition(); + pos.pos[0] = playerPos[0]; + pos.pos[1] = playerPos[1]; + pos.pos[2] = playerPos[2]; + + mWorldScene->insertObject(object, cell); + } } diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index cb849cc1b4..cc6a665fc1 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -269,6 +269,17 @@ namespace MWWorld void update (float duration); + bool placeObject(MWWorld::Ptr object, float cursorX, float cursorY); + ///< place an object into the gameworld at the specified cursor position + /// @param object + /// @param cursor X (relative 0-1) + /// @param cursor Y (relative 0-1) + /// @return true if the object was placed, or false if it was rejected because the position is too far away + + void dropObjectOnGround(MWWorld::Ptr object); + + bool canPlaceObject(float cursorX, float cursorY); + ///< @return true if it is possible to place on object at specified cursor location }; } diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp index 651d9a3181..8af3526a0f 100644 --- a/components/esm/loadcrea.cpp +++ b/components/esm/loadcrea.cpp @@ -19,9 +19,15 @@ void Creature::load(ESMReader &esm, const std::string& id) inventory.load(esm); - // More subrecords: + if (esm.isNextSub("AIDT")) + { + esm.getHExact(&AI, sizeof(AI)); + hasAI = true; + } + else + hasAI = false; - // AIDT - data (12 bytes, unknown) + // More subrecords: // AI_W - wander (14 bytes, i don't understand it) // short distance // byte duration @@ -33,8 +39,8 @@ void Creature::load(ESMReader &esm, const std::string& id) // AI_F - follow? // AI_E - escort? // AI_A - activate? - esm.skipRecord(); + } } diff --git a/components/esm/loadcrea.hpp b/components/esm/loadcrea.hpp index 3c334ebbd4..c3c5b181e0 100644 --- a/components/esm/loadcrea.hpp +++ b/components/esm/loadcrea.hpp @@ -51,6 +51,15 @@ struct Creature int gold; }; // 96 bytes + struct AIDTstruct + { + // These are probabilities + char hello, u1, fight, flee, alarm, u2, u3, u4; + // The last u's might be the skills that this NPC can train you + // in? + int services; // See the NPC::Services enum + }; // 12 bytes + NPDTstruct data; int flags; @@ -61,6 +70,9 @@ struct Creature // Defined in loadcont.hpp InventoryList inventory; + bool hasAI; + AIDTstruct AI; + std::string mId; void load(ESMReader &esm, const std::string& id); diff --git a/components/esm/loadskil.cpp b/components/esm/loadskil.cpp index aa7103efcb..52869f4404 100644 --- a/components/esm/loadskil.cpp +++ b/components/esm/loadskil.cpp @@ -31,6 +31,35 @@ namespace ESM "sSkillSpeechcraft", "sSkillHandtohand", }; + const std::string Skill::sIconNames[Length] = { + "combat_block.dds", + "combat_armor.dds", + "combat_mediumarmor.dds", + "combat_heavyarmor.dds", + "combat_blunt.dds", + "combat_longblade.dds", + "combat_axe.dds", + "combat_spear.dds", + "combat_athletics.dds", + "magic_enchant.dds", + "magic_destruction.dds", + "magic_alteration.dds", + "magic_illusion.dds", + "magic_conjuration.dds", + "magic_mysticism.dds", + "magic_restoration.dds", + "magic_alchemy.dds", + "magic_unarmored.dds", + "stealth_security.dds", + "stealth_sneak.dds", + "stealth_acrobatics.dds", + "stealth_lightarmor.dds", + "stealth_shortblade.dds", + "stealth_marksman.dds", + "stealth_mercantile.dds", + "stealth_speechcraft.dds", + "stealth_handtohand.dds", + }; const boost::array Skill::skillIds = {{ Block, Armorer, diff --git a/components/esm/loadskil.hpp b/components/esm/loadskil.hpp index 836f702051..f56ec2fcb9 100644 --- a/components/esm/loadskil.hpp +++ b/components/esm/loadskil.hpp @@ -64,6 +64,7 @@ struct Skill Length }; static const std::string sSkillNameIds[Length]; + static const std::string sIconNames[Length]; static const boost::array skillIds; void load(ESMReader &esm); diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index ac803646e4..cacfb7c5a3 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -36,6 +36,7 @@ configure_file("${SDIR}/openmw_chargen_review_layout.xml" "${DDIR}/openmw_charge configure_file("${SDIR}/openmw_dialogue_window_layout.xml" "${DDIR}/openmw_dialogue_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_dialogue_window_skin.xml" "${DDIR}/openmw_dialogue_window_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_inventory_window_layout.xml" "${DDIR}/openmw_inventory_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_container_window_layout.xml" "${DDIR}/openmw_container_window_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_layers.xml" "${DDIR}/openmw_layers.xml" COPYONLY) configure_file("${SDIR}/openmw_mainmenu_layout.xml" "${DDIR}/openmw_mainmenu_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_mainmenu_skin.xml" "${DDIR}/openmw_mainmenu_skin.xml" COPYONLY) @@ -54,6 +55,8 @@ configure_file("${SDIR}/openmw_tooltips.xml" "${DDIR}/openmw_tooltips.xml" COPYO configure_file("${SDIR}/openmw_scroll_layout.xml" "${DDIR}/openmw_scroll_layout.xml" COPYONLY) configure_file("${SDIR}/openmw_scroll_skin.xml" "${DDIR}/openmw_scroll_skin.xml" COPYONLY) configure_file("${SDIR}/openmw_book_layout.xml" "${DDIR}/openmw_book_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_count_window_layout.xml" "${DDIR}/openmw_count_window_layout.xml" COPYONLY) +configure_file("${SDIR}/openmw_trade_window_layout.xml" "${DDIR}/openmw_trade_window_layout.xml" COPYONLY) configure_file("${SDIR}/atlas1.cfg" "${DDIR}/atlas1.cfg" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw.font.xml index 252499a5f1..73d491e04e 100644 --- a/files/mygui/openmw.font.xml +++ b/files/mygui/openmw.font.xml @@ -13,6 +13,7 @@ + diff --git a/files/mygui/openmw.pointer.xml b/files/mygui/openmw.pointer.xml index 0fbef2fdf5..42ee5d4351 100644 --- a/files/mygui/openmw.pointer.xml +++ b/files/mygui/openmw.pointer.xml @@ -26,4 +26,9 @@ + + + + + diff --git a/files/mygui/openmw_box.skin.xml b/files/mygui/openmw_box.skin.xml index c1952794c1..2a54edd60b 100644 --- a/files/mygui/openmw_box.skin.xml +++ b/files/mygui/openmw_box.skin.xml @@ -6,23 +6,39 @@ as around the sections of the stats window, or around popup info windows --> - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index b88e994066..491b3f47b7 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -3,23 +3,39 @@ - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + @@ -62,6 +78,10 @@ + + + + diff --git a/files/mygui/openmw_chargen_birth_layout.xml b/files/mygui/openmw_chargen_birth_layout.xml index bce3f585dc..0599ab8638 100644 --- a/files/mygui/openmw_chargen_birth_layout.xml +++ b/files/mygui/openmw_chargen_birth_layout.xml @@ -15,7 +15,7 @@ - + diff --git a/files/mygui/openmw_chargen_class_layout.xml b/files/mygui/openmw_chargen_class_layout.xml index bf49810c80..38fa606abe 100644 --- a/files/mygui/openmw_chargen_class_layout.xml +++ b/files/mygui/openmw_chargen_class_layout.xml @@ -55,7 +55,7 @@ - + diff --git a/files/mygui/openmw_chargen_create_class_layout.xml b/files/mygui/openmw_chargen_create_class_layout.xml index 3b7d91b00c..be6a10e0c9 100644 --- a/files/mygui/openmw_chargen_create_class_layout.xml +++ b/files/mygui/openmw_chargen_create_class_layout.xml @@ -56,7 +56,7 @@ - + diff --git a/files/mygui/openmw_chargen_generate_class_result_layout.xml b/files/mygui/openmw_chargen_generate_class_result_layout.xml index 26ebe17e1f..9a6ed4f2ec 100644 --- a/files/mygui/openmw_chargen_generate_class_result_layout.xml +++ b/files/mygui/openmw_chargen_generate_class_result_layout.xml @@ -21,7 +21,7 @@ - + diff --git a/files/mygui/openmw_chargen_race_layout.xml b/files/mygui/openmw_chargen_race_layout.xml index 6887b12c5c..a9b072f5e2 100644 --- a/files/mygui/openmw_chargen_race_layout.xml +++ b/files/mygui/openmw_chargen_race_layout.xml @@ -61,7 +61,7 @@ - + diff --git a/files/mygui/openmw_chargen_review_layout.xml b/files/mygui/openmw_chargen_review_layout.xml index c713eb4772..57bb3b1246 100644 --- a/files/mygui/openmw_chargen_review_layout.xml +++ b/files/mygui/openmw_chargen_review_layout.xml @@ -5,10 +5,18 @@ - - - - + + + + + + + + + + + + @@ -17,9 +25,15 @@ - - - + + + + + + + + + @@ -42,7 +56,7 @@ - + diff --git a/files/mygui/openmw_container_window_layout.xml b/files/mygui/openmw_container_window_layout.xml new file mode 100644 index 0000000000..ae9b0bfdf9 --- /dev/null +++ b/files/mygui/openmw_container_window_layout.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_count_window_layout.xml b/files/mygui/openmw_count_window_layout.xml new file mode 100644 index 0000000000..38ba7644f6 --- /dev/null +++ b/files/mygui/openmw_count_window_layout.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window_layout.xml index d45de4bd44..1271a287b6 100644 --- a/files/mygui/openmw_dialogue_window_layout.xml +++ b/files/mygui/openmw_dialogue_window_layout.xml @@ -24,7 +24,7 @@ - + diff --git a/files/mygui/openmw_hud_box.skin.xml b/files/mygui/openmw_hud_box.skin.xml index bf1b0056a0..86b63fcf6e 100644 --- a/files/mygui/openmw_hud_box.skin.xml +++ b/files/mygui/openmw_hud_box.skin.xml @@ -3,18 +3,38 @@ - - + + + + + + - - + + + + + + + - - + + + + + + + - - + + + + + + + + diff --git a/files/mygui/openmw_hud_layout.xml b/files/mygui/openmw_hud_layout.xml index 2dafa72988..0aabc3e3ee 100644 --- a/files/mygui/openmw_hud_layout.xml +++ b/files/mygui/openmw_hud_layout.xml @@ -3,12 +3,30 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -62,7 +80,10 @@ - + + + + @@ -85,9 +106,9 @@ - - + + + - + + + + + + + + + + + + + + + - - - - - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - diff --git a/files/mygui/openmw_layers.xml b/files/mygui/openmw_layers.xml index a83eb970a8..a5044fb78e 100644 --- a/files/mygui/openmw_layers.xml +++ b/files/mygui/openmw_layers.xml @@ -8,6 +8,6 @@ + - diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 89cc73123c..e1fbc49b63 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -6,13 +6,32 @@ - - + + + + + + + + + + + + + + + + + + + + + @@ -131,6 +150,7 @@ + @@ -143,7 +163,7 @@ - + diff --git a/files/mygui/openmw_map_window_layout.xml b/files/mygui/openmw_map_window_layout.xml index fbba8ddf47..e0ae5bd881 100644 --- a/files/mygui/openmw_map_window_layout.xml +++ b/files/mygui/openmw_map_window_layout.xml @@ -31,7 +31,9 @@ - + + + diff --git a/files/mygui/openmw_resources.xml b/files/mygui/openmw_resources.xml index b2bd90d105..4c509ae13d 100644 --- a/files/mygui/openmw_resources.xml +++ b/files/mygui/openmw_resources.xml @@ -36,6 +36,13 @@ + + + + + + + diff --git a/files/mygui/openmw_scroll_skin.xml b/files/mygui/openmw_scroll_skin.xml index 39437d54e7..70fad3f4b4 100644 --- a/files/mygui/openmw_scroll_skin.xml +++ b/files/mygui/openmw_scroll_skin.xml @@ -4,8 +4,12 @@ - + + + + + diff --git a/files/mygui/openmw_stats_window_layout.xml b/files/mygui/openmw_stats_window_layout.xml index 9406fe6bdd..4729e3bca8 100644 --- a/files/mygui/openmw_stats_window_layout.xml +++ b/files/mygui/openmw_stats_window_layout.xml @@ -7,25 +7,95 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index 36d97e1538..6b62f618db 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -1,6 +1,8 @@ + + @@ -15,6 +17,7 @@ + diff --git a/files/mygui/openmw_tooltips.xml b/files/mygui/openmw_tooltips.xml index 2d5a5da9f2..a1673d3462 100644 --- a/files/mygui/openmw_tooltips.xml +++ b/files/mygui/openmw_tooltips.xml @@ -8,6 +8,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_trade_window_layout.xml b/files/mygui/openmw_trade_window_layout.xml new file mode 100644 index 0000000000..c8a9f25234 --- /dev/null +++ b/files/mygui/openmw_trade_window_layout.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index 7c194ea5d0..b379f84ced 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -17,14 +17,22 @@ - - + + + + + + - - + + + + + + @@ -66,29 +74,45 @@ - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + @@ -120,20 +144,32 @@ - - + + + + + + - - + + + + + + - - + + + + + + @@ -171,12 +207,8 @@ - - - - - - + + @@ -218,6 +250,7 @@ + @@ -294,6 +327,7 @@ + diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index bda8935af2..d9eefe0510 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -71,7 +71,7 @@ namespace GUI void shutdown() { - MyGUI::LayoutManager::getInstance().unloadLayout(mListWindowRoot); + MyGUI::Gui::getInstance().destroyWidget(mMainWidget); mListWindowRoot.clear(); } @@ -115,6 +115,13 @@ namespace GUI static_cast(pt)->setCaption(caption); } + void setTitle(const std::string& title) + { + // NOTE: this assume that mMainWidget is of type Window. + static_cast(mMainWidget)->setCaption(title); + adjustWindowCaption(); + } + void setState(const std::string& widget, const std::string& state) { MyGUI::Widget* pt;