mirror of
https://github.com/OpenMW/openmw.git
synced 2025-06-01 09:41:35 +00:00
Allow equipping twohanded weapon and shield at the same time (Fixes #1785)
The shield can be equipped, meaning armor rating and item enchantments apply, but can not be blocked with.
This commit is contained in:
parent
bc85bb32c2
commit
d034a079e6
12 changed files with 61 additions and 25 deletions
|
@ -205,6 +205,8 @@ namespace MWBase
|
||||||
|
|
||||||
/// Resurrects the player if necessary
|
/// Resurrects the player if necessary
|
||||||
virtual void keepPlayerAlive() = 0;
|
virtual void keepPlayerAlive() = 0;
|
||||||
|
|
||||||
|
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1554,4 +1554,13 @@ namespace MWMechanics
|
||||||
if (ptr.getClass().isNpc())
|
if (ptr.getClass().isNpc())
|
||||||
calculateNpcStatModifiers(ptr, 0.f);
|
calculateNpcStatModifiers(ptr, 0.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
PtrControllerMap::const_iterator it = mActors.find(ptr);
|
||||||
|
if (it == mActors.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return it->second->isReadyToBlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,6 +125,8 @@ namespace MWMechanics
|
||||||
|
|
||||||
void clear(); // Clear death counter
|
void clear(); // Clear death counter
|
||||||
|
|
||||||
|
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PtrControllerMap mActors;
|
PtrControllerMap mActors;
|
||||||
|
|
||||||
|
|
|
@ -648,7 +648,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
mAnimation->showWeapons(true);
|
mAnimation->showWeapons(true);
|
||||||
mAnimation->setWeaponGroup(mCurrentWeapon);
|
mAnimation->setWeaponGroup(mCurrentWeapon);
|
||||||
}
|
}
|
||||||
mAnimation->showCarriedLeft(mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand);
|
|
||||||
|
mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cls.getCreatureStats(mPtr).isDead())
|
if(!cls.getCreatureStats(mPtr).isDead())
|
||||||
|
@ -836,6 +837,25 @@ bool CharacterController::updateCreatureState()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CharacterController::updateCarriedLeftVisible(WeaponType weaptype) const
|
||||||
|
{
|
||||||
|
// Shields/torches shouldn't be visible during any operation involving two hands
|
||||||
|
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
|
||||||
|
// but they are also present in weapon drawing animation.
|
||||||
|
switch (weaptype)
|
||||||
|
{
|
||||||
|
case WeapType_Spell:
|
||||||
|
case WeapType_BowAndArrow:
|
||||||
|
case WeapType_Crossbow:
|
||||||
|
case WeapType_HandToHand:
|
||||||
|
case WeapType_TwoHand:
|
||||||
|
case WeapType_TwoWide:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CharacterController::updateWeaponState()
|
bool CharacterController::updateWeaponState()
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = mPtr.getClass();
|
const MWWorld::Class &cls = mPtr.getClass();
|
||||||
|
@ -850,10 +870,7 @@ bool CharacterController::updateWeaponState()
|
||||||
{
|
{
|
||||||
forcestateupdate = true;
|
forcestateupdate = true;
|
||||||
|
|
||||||
// Shields/torches shouldn't be visible during spellcasting or hand-to-hand
|
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
|
||||||
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
|
|
||||||
// but they are also present in weapon drawing animation.
|
|
||||||
mAnimation->showCarriedLeft(weaptype != WeapType_Spell && weaptype != WeapType_HandToHand);
|
|
||||||
|
|
||||||
std::string weapgroup;
|
std::string weapgroup;
|
||||||
if(weaptype == WeapType_None)
|
if(weaptype == WeapType_None)
|
||||||
|
@ -1818,4 +1835,9 @@ void CharacterController::determineAttackType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CharacterController::isReadyToBlock() const
|
||||||
|
{
|
||||||
|
return updateCarriedLeftVisible(mWeaponType);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,6 +199,8 @@ class CharacterController
|
||||||
/// @param num if non-NULL, the chosen animation number will be written here
|
/// @param num if non-NULL, the chosen animation number will be written here
|
||||||
std::string chooseRandomGroup (const std::string& prefix, int* num = NULL);
|
std::string chooseRandomGroup (const std::string& prefix, int* num = NULL);
|
||||||
|
|
||||||
|
bool updateCarriedLeftVisible(WeaponType weaptype) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||||
virtual ~CharacterController();
|
virtual ~CharacterController();
|
||||||
|
@ -224,6 +226,8 @@ public:
|
||||||
void forceStateUpdate();
|
void forceStateUpdate();
|
||||||
|
|
||||||
AiState& getAiState() { return mAiState; }
|
AiState& getAiState() { return mAiState; }
|
||||||
|
|
||||||
|
bool isReadyToBlock() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
void getWeaponGroup(WeaponType weaptype, std::string &group);
|
void getWeaponGroup(WeaponType weaptype, std::string &group);
|
||||||
|
|
|
@ -62,17 +62,10 @@ namespace MWMechanics
|
||||||
|| blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
|
|| blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Don't block when in spellcasting state (shield is equipped, but not visible)
|
if (!MWBase::Environment::get().getMechanicsManager()->isReadyToBlock(blocker))
|
||||||
if (blockerStats.getDrawState() == DrawState_Spell)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
MWWorld::InventoryStore& inv = blocker.getClass().getInventoryStore(blocker);
|
MWWorld::InventoryStore& inv = blocker.getClass().getInventoryStore(blocker);
|
||||||
|
|
||||||
// Don't block when in hand-to-hand combat (shield is equipped, but not visible)
|
|
||||||
if (blockerStats.getDrawState() == DrawState_Weapon &&
|
|
||||||
inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight) == inv.end())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||||
if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name())
|
if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1352,4 +1352,9 @@ namespace MWMechanics
|
||||||
stats.resurrect();
|
stats.resurrect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const
|
||||||
|
{
|
||||||
|
return mActors.isReadyToBlock(ptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,6 +169,8 @@ namespace MWMechanics
|
||||||
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false);
|
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false);
|
||||||
|
|
||||||
virtual void keepPlayerAlive();
|
virtual void keepPlayerAlive();
|
||||||
|
|
||||||
|
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,6 +195,7 @@ namespace MWRender
|
||||||
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
|
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
|
||||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
std::string groupname;
|
std::string groupname;
|
||||||
|
bool showCarriedLeft = true;
|
||||||
if(iter == inv.end())
|
if(iter == inv.end())
|
||||||
groupname = "inventoryhandtohand";
|
groupname = "inventoryhandtohand";
|
||||||
else
|
else
|
||||||
|
@ -224,11 +225,15 @@ namespace MWRender
|
||||||
groupname = "inventoryweapontwowide";
|
groupname = "inventoryweapontwowide";
|
||||||
else
|
else
|
||||||
groupname = "inventoryhandtohand";
|
groupname = "inventoryhandtohand";
|
||||||
|
|
||||||
|
showCarriedLeft = (iter->getClass().canBeEquipped(*iter, mCharacter).first != 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
groupname = "inventoryhandtohand";
|
groupname = "inventoryhandtohand";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mAnimation->showCarriedLeft(showCarriedLeft);
|
||||||
|
|
||||||
mCurrentAnimGroup = groupname;
|
mCurrentAnimGroup = groupname;
|
||||||
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0);
|
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0);
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ public:
|
||||||
virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
|
virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
virtual void showCarriedLeft(bool showa);
|
virtual void showCarriedLeft(bool show);
|
||||||
|
|
||||||
virtual void attachArrow();
|
virtual void attachArrow();
|
||||||
virtual void releaseArrow();
|
virtual void releaseArrow();
|
||||||
|
|
|
@ -31,11 +31,7 @@ namespace MWWorld
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return;
|
return;
|
||||||
case 2:
|
default:
|
||||||
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft, actor);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, actor);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,11 +255,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
continue;
|
continue;
|
||||||
case 2:
|
default:
|
||||||
slots_[MWWorld::InventoryStore::Slot_CarriedLeft] = end();
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
// Prefer keeping twohanded weapon
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue