mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 21:59:55 +00:00
Implement weapon/spell cycling hotkeys (Fixes #1024)
This commit is contained in:
parent
4d5adfb5dd
commit
935cccf974
11 changed files with 148 additions and 12 deletions
|
@ -342,6 +342,11 @@ namespace MWBase
|
|||
virtual void setWerewolfOverlay(bool set) = 0;
|
||||
|
||||
virtual void toggleDebugWindow() = 0;
|
||||
|
||||
/// Cycle to next or previous spell
|
||||
virtual void cycleSpell(bool next) = 0;
|
||||
/// Cycle to next or previous weapon
|
||||
virtual void cycleWeapon(bool next) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,19 @@
|
|||
#include "tradewindow.hpp"
|
||||
#include "container.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool isRightHandWeapon(const MWWorld::Ptr& item)
|
||||
{
|
||||
if (item.getClass().getTypeName() != typeid(ESM::Weapon).name())
|
||||
return false;
|
||||
std::vector<int> equipmentSlots = item.getClass().getEquipmentSlots(item).first;
|
||||
return (!equipmentSlots.empty() && equipmentSlots.front() == MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
{
|
||||
|
||||
|
@ -599,4 +612,39 @@ namespace MWGui
|
|||
|
||||
MWBase::Environment::get().getMechanicsManager()->itemTaken(player, newObject, count);
|
||||
}
|
||||
|
||||
void InventoryWindow::cycle(bool next)
|
||||
{
|
||||
ItemModel::ModelIndex selected = 0;
|
||||
// not using mSortFilterModel as we only need sorting, not filtering
|
||||
SortFilterItemModel model(new InventoryItemModel(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
||||
model.setSortByType(false);
|
||||
model.update();
|
||||
if (model.getItemCount() == 0)
|
||||
return;
|
||||
for (ItemModel::ModelIndex i=0; i<int(model.getItemCount()); ++i)
|
||||
{
|
||||
MWWorld::Ptr item = model.getItem(i).mBase;
|
||||
if (model.getItem(i).mType & ItemStack::Type_Equipped && isRightHandWeapon(item))
|
||||
selected = i;
|
||||
}
|
||||
|
||||
int incr = next ? 1 : -1;
|
||||
bool found = false;
|
||||
ItemModel::ModelIndex cycled = selected;
|
||||
while (!found)
|
||||
{
|
||||
cycled += incr;
|
||||
cycled = (cycled + model.getItemCount()) % model.getItemCount();
|
||||
|
||||
MWWorld::Ptr item = model.getItem(cycled).mBase;
|
||||
if (item.getClass().getTypeName() == typeid(ESM::Weapon).name() && isRightHandWeapon(item))
|
||||
found = true;
|
||||
|
||||
if (cycled == selected) // we've been through all items, nothing found
|
||||
return;
|
||||
}
|
||||
|
||||
useItem(model.getItem(cycled).mBase);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@ namespace MWGui
|
|||
|
||||
void setGuiMode(GuiMode mode);
|
||||
|
||||
/// Cycle to previous/next weapon
|
||||
void cycle(bool next);
|
||||
|
||||
private:
|
||||
DragAndDrop* mDragAndDrop;
|
||||
|
||||
|
|
|
@ -41,20 +41,25 @@ namespace
|
|||
return std::find(mapping.begin(), mapping.end(), type1) < std::find(mapping.begin(), mapping.end(), type2);
|
||||
}
|
||||
|
||||
bool compare (const MWGui::ItemStack& left, const MWGui::ItemStack& right)
|
||||
struct Compare
|
||||
{
|
||||
if (left.mType != right.mType)
|
||||
return left.mType < right.mType;
|
||||
|
||||
if (left.mBase.getTypeName() == right.mBase.getTypeName())
|
||||
bool mSortByType;
|
||||
Compare() : mSortByType(true) {}
|
||||
bool operator() (const MWGui::ItemStack& left, const MWGui::ItemStack& right)
|
||||
{
|
||||
int cmp = left.mBase.getClass().getName(left.mBase).compare(
|
||||
right.mBase.getClass().getName(right.mBase));
|
||||
return cmp < 0;
|
||||
if (mSortByType && left.mType != right.mType)
|
||||
return left.mType < right.mType;
|
||||
|
||||
if (left.mBase.getTypeName() == right.mBase.getTypeName())
|
||||
{
|
||||
int cmp = left.mBase.getClass().getName(left.mBase).compare(
|
||||
right.mBase.getClass().getName(right.mBase));
|
||||
return cmp < 0;
|
||||
}
|
||||
else
|
||||
return compareType(left.mBase.getTypeName(), right.mBase.getTypeName());
|
||||
}
|
||||
else
|
||||
return compareType(left.mBase.getTypeName(), right.mBase.getTypeName());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWGui
|
||||
|
@ -63,6 +68,7 @@ namespace MWGui
|
|||
SortFilterItemModel::SortFilterItemModel(ItemModel *sourceModel)
|
||||
: mCategory(Category_All)
|
||||
, mShowEquipped(true)
|
||||
, mSortByType(true)
|
||||
, mFilter(0)
|
||||
{
|
||||
mSourceModel = sourceModel;
|
||||
|
@ -183,7 +189,9 @@ namespace MWGui
|
|||
mItems.push_back(item);
|
||||
}
|
||||
|
||||
std::sort(mItems.begin(), mItems.end(), compare);
|
||||
Compare cmp;
|
||||
cmp.mSortByType = mSortByType;
|
||||
std::sort(mItems.begin(), mItems.end(), cmp);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@ namespace MWGui
|
|||
void setFilter (int filter);
|
||||
void setShowEquipped (bool show) { mShowEquipped = show; }
|
||||
|
||||
/// Use ItemStack::Type for sorting?
|
||||
void setSortByType(bool sort) { mSortByType = sort; }
|
||||
|
||||
static const int Category_Weapon = (1<<1);
|
||||
static const int Category_Apparel = (1<<2);
|
||||
static const int Category_Misc = (1<<3);
|
||||
|
@ -47,6 +50,7 @@ namespace MWGui
|
|||
int mCategory;
|
||||
int mFilter;
|
||||
bool mShowEquipped;
|
||||
bool mSortByType;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -97,6 +97,10 @@ namespace MWGui
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!item.getClass().getEquipmentSlots(item).first.empty()
|
||||
&& item.getClass().canBeEquipped(item, mActor).first == 0)
|
||||
continue;
|
||||
|
||||
float enchantCost = enchant->mData.mCost;
|
||||
int eSkill = mActor.getClass().getSkill(mActor, ESM::Skill::Enchant);
|
||||
int castCost = std::max(1.f, enchantCost - (enchantCost / 100) * (eSkill - 10));
|
||||
|
|
|
@ -160,4 +160,25 @@ namespace MWGui
|
|||
|
||||
updateSpells();
|
||||
}
|
||||
|
||||
void SpellWindow::cycle(bool next)
|
||||
{
|
||||
mSpellView->setModel(new SpellModel(MWBase::Environment::get().getWorld()->getPlayerPtr()));
|
||||
mSpellView->getModel()->update();
|
||||
|
||||
SpellModel::ModelIndex selected = 0;
|
||||
for (SpellModel::ModelIndex i = 0; i<int(mSpellView->getModel()->getItemCount()); ++i)
|
||||
{
|
||||
if (mSpellView->getModel()->getItem(i).mSelected)
|
||||
selected = i;
|
||||
}
|
||||
|
||||
selected += next ? 1 : -1;
|
||||
int itemcount = mSpellView->getModel()->getItemCount();
|
||||
if (itemcount == 0)
|
||||
return;
|
||||
selected = (selected + itemcount) % itemcount;
|
||||
|
||||
onModelIndexSelected(selected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace MWGui
|
|||
|
||||
void onFrame(float dt) { NoDrop::onFrame(dt); }
|
||||
|
||||
/// Cycle to next/previous spell
|
||||
void cycle(bool next);
|
||||
|
||||
protected:
|
||||
MyGUI::Widget* mEffectBox;
|
||||
|
||||
|
|
|
@ -1820,4 +1820,14 @@ namespace MWGui
|
|||
mDebugWindow->setVisible(!mDebugWindow->isVisible());
|
||||
}
|
||||
|
||||
void WindowManager::cycleSpell(bool next)
|
||||
{
|
||||
mSpellWindow->cycle(next);
|
||||
}
|
||||
|
||||
void WindowManager::cycleWeapon(bool next)
|
||||
{
|
||||
mInventoryWindow->cycle(next);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -338,6 +338,11 @@ namespace MWGui
|
|||
|
||||
virtual void toggleDebugWindow();
|
||||
|
||||
/// Cycle to next or previous spell
|
||||
virtual void cycleSpell(bool next);
|
||||
/// Cycle to next or previous weapon
|
||||
virtual void cycleWeapon(bool next);
|
||||
|
||||
private:
|
||||
bool mConsoleOnlyScripts;
|
||||
|
||||
|
|
|
@ -286,6 +286,18 @@ namespace MWInput
|
|||
case A_QuickLoad:
|
||||
quickLoad();
|
||||
break;
|
||||
case A_CycleSpellLeft:
|
||||
MWBase::Environment::get().getWindowManager()->cycleSpell(false);
|
||||
break;
|
||||
case A_CycleSpellRight:
|
||||
MWBase::Environment::get().getWindowManager()->cycleSpell(true);
|
||||
break;
|
||||
case A_CycleWeaponLeft:
|
||||
MWBase::Environment::get().getWindowManager()->cycleWeapon(false);
|
||||
break;
|
||||
case A_CycleWeaponRight:
|
||||
MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -894,6 +906,11 @@ namespace MWInput
|
|||
defaultKeyBindings[A_MoveRight] = SDL_SCANCODE_D;
|
||||
defaultKeyBindings[A_ToggleWeapon] = SDL_SCANCODE_F;
|
||||
defaultKeyBindings[A_ToggleSpell] = SDL_SCANCODE_R;
|
||||
defaultKeyBindings[A_CycleSpellLeft] = SDL_SCANCODE_MINUS;
|
||||
defaultKeyBindings[A_CycleSpellRight] = SDL_SCANCODE_EQUALS;
|
||||
defaultKeyBindings[A_CycleWeaponLeft] = SDL_SCANCODE_LEFTBRACKET;
|
||||
defaultKeyBindings[A_CycleWeaponRight] = SDL_SCANCODE_RIGHTBRACKET;
|
||||
|
||||
defaultKeyBindings[A_QuickKeysMenu] = SDL_SCANCODE_F1;
|
||||
defaultKeyBindings[A_Console] = SDL_SCANCODE_GRAVE;
|
||||
defaultKeyBindings[A_Run] = SDL_SCANCODE_LSHIFT;
|
||||
|
@ -972,6 +989,10 @@ namespace MWInput
|
|||
descriptions[A_MoveRight] = "sRight";
|
||||
descriptions[A_ToggleWeapon] = "sReady_Weapon";
|
||||
descriptions[A_ToggleSpell] = "sReady_Magic";
|
||||
descriptions[A_CycleSpellLeft] = "sPrevSpell";
|
||||
descriptions[A_CycleSpellRight] = "sNextSpell";
|
||||
descriptions[A_CycleWeaponLeft] = "sPrevWeapon";
|
||||
descriptions[A_CycleWeaponRight] = "sNextWeapon";
|
||||
descriptions[A_Console] = "sConsoleTitle";
|
||||
descriptions[A_Run] = "sRun";
|
||||
descriptions[A_Sneak] = "sCrouch_Sneak";
|
||||
|
@ -1032,6 +1053,10 @@ namespace MWInput
|
|||
ret.push_back(A_Use);
|
||||
ret.push_back(A_ToggleWeapon);
|
||||
ret.push_back(A_ToggleSpell);
|
||||
ret.push_back(A_CycleSpellLeft);
|
||||
ret.push_back(A_CycleSpellRight);
|
||||
ret.push_back(A_CycleWeaponLeft);
|
||||
ret.push_back(A_CycleWeaponRight);
|
||||
ret.push_back(A_AutoMove);
|
||||
ret.push_back(A_Jump);
|
||||
ret.push_back(A_Inventory);
|
||||
|
|
Loading…
Reference in a new issue