1
0
Fork 0
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:
scrawl 2014-12-15 15:23:03 +01:00
parent 4d5adfb5dd
commit 935cccf974
11 changed files with 148 additions and 12 deletions

View file

@ -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;
};
}

View file

@ -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);
}
}

View file

@ -49,6 +49,9 @@ namespace MWGui
void setGuiMode(GuiMode mode);
/// Cycle to previous/next weapon
void cycle(bool next);
private:
DragAndDrop* mDragAndDrop;

View file

@ -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);
}
}

View file

@ -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;
};
}

View file

@ -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));

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);