forked from teamnwah/openmw-tes3coop
Feature #50: Handle attach & release of projectiles
This commit is contained in:
parent
8b8fb931a0
commit
ffe19e7a52
7 changed files with 96 additions and 26 deletions
|
@ -836,6 +836,9 @@ bool CharacterController::updateWeaponState()
|
||||||
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
||||||
mUpperBodyState == UpperCharState_CastingSpell)
|
mUpperBodyState == UpperCharState_CastingSpell)
|
||||||
{
|
{
|
||||||
|
if (ammunition && mWeaponType == WeapType_Crossbow)
|
||||||
|
mAnimation->attachArrow();
|
||||||
|
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it
|
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it
|
||||||
if(mHitState == CharState_Hit)
|
if(mHitState == CharState_Hit)
|
||||||
|
|
|
@ -695,6 +695,12 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
|
||||||
else
|
else
|
||||||
mPtr.getClass().hit(mPtr);
|
mPtr.getClass().hit(mPtr);
|
||||||
}
|
}
|
||||||
|
else if (evt.compare(off, len, "shoot attach") == 0)
|
||||||
|
attachArrow();
|
||||||
|
else if (evt.compare(off, len, "shoot release") == 0)
|
||||||
|
releaseArrow();
|
||||||
|
else if (evt.compare(off, len, "shoot follow attach") == 0)
|
||||||
|
attachArrow();
|
||||||
|
|
||||||
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
else if (groupname == "spellcast" && evt.substr(evt.size()-7, 7) == "release")
|
||||||
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
||||||
|
|
|
@ -295,7 +295,8 @@ public:
|
||||||
|
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
virtual void showCarriedLeft(bool show) {}
|
virtual void showCarriedLeft(bool show) {}
|
||||||
|
virtual void attachArrow() {}
|
||||||
|
virtual void releaseArrow() {}
|
||||||
void enableLights(bool enable);
|
void enableLights(bool enable);
|
||||||
|
|
||||||
Ogre::AxisAlignedBox getWorldBounds();
|
Ogre::AxisAlignedBox getWorldBounds();
|
||||||
|
|
|
@ -696,6 +696,17 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
|
||||||
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
|
||||||
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
|
||||||
|
|
||||||
|
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||||
|
{
|
||||||
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||||
|
attachArrow();
|
||||||
|
else
|
||||||
|
mAmmunition.setNull();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mAmmunition.setNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -726,6 +737,52 @@ void NpcAnimation::showCarriedLeft(bool show)
|
||||||
removeIndividualPart(ESM::PRT_Shield);
|
removeIndividualPart(ESM::PRT_Shield);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NpcAnimation::attachArrow()
|
||||||
|
{
|
||||||
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||||
|
MWWorld::ContainerStoreIterator weaponSlot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if (weaponSlot != inv.end() && weaponSlot->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||||
|
showWeapons(true);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NifOgre::ObjectScenePtr weapon = mObjectParts[ESM::PRT_Weapon];
|
||||||
|
|
||||||
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
if (ammo == inv.end())
|
||||||
|
return;
|
||||||
|
std::string model = ammo->getClass().getModel(*ammo);
|
||||||
|
|
||||||
|
mAmmunition = NifOgre::Loader::createObjects(weapon->mSkelBase, "ArrowBone", mInsert, model);
|
||||||
|
Ogre::Vector3 glowColor = getEnchantmentColor(*ammo);
|
||||||
|
setRenderProperties(mAmmunition, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
|
||||||
|
!ammo->getClass().getEnchantment(*ammo).empty(), &glowColor);
|
||||||
|
|
||||||
|
std::for_each(mAmmunition->mEntities.begin(), mAmmunition->mEntities.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
||||||
|
std::for_each(mAmmunition->mParticles.begin(), mAmmunition->mParticles.end(), SetObjectGroup(MWWorld::InventoryStore::Slot_Ammunition));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NpcAnimation::releaseArrow()
|
||||||
|
{
|
||||||
|
// Thrown weapons get detached now
|
||||||
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||||
|
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if (weapon != inv.end() && weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||||
|
{
|
||||||
|
showWeapons(false);
|
||||||
|
inv.remove(*weapon, 1, mPtr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// With bows and crossbows only the used arrow/bolt gets detached
|
||||||
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
if (ammo == inv.end())
|
||||||
|
return;
|
||||||
|
inv.remove(*ammo, 1, mPtr);
|
||||||
|
mAmmunition.setNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
void NpcAnimation::permanentEffectAdded(const ESM::MagicEffect *magicEffect, bool isNew, bool playSound)
|
||||||
{
|
{
|
||||||
// During first auto equip, we don't play any sounds.
|
// During first auto equip, we don't play any sounds.
|
||||||
|
|
|
@ -135,6 +135,11 @@ public:
|
||||||
virtual void showWeapons(bool showWeapon);
|
virtual void showWeapons(bool showWeapon);
|
||||||
virtual void showCarriedLeft(bool showa);
|
virtual void showCarriedLeft(bool showa);
|
||||||
|
|
||||||
|
virtual void attachArrow();
|
||||||
|
virtual void releaseArrow();
|
||||||
|
|
||||||
|
NifOgre::ObjectScenePtr mAmmunition;
|
||||||
|
|
||||||
void setViewMode(ViewMode viewMode);
|
void setViewMode(ViewMode viewMode);
|
||||||
|
|
||||||
void updateParts();
|
void updateParts();
|
||||||
|
|
|
@ -462,6 +462,10 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem(
|
||||||
|
|
||||||
int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor)
|
int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor)
|
||||||
{
|
{
|
||||||
|
int retCount = ContainerStore::remove(item, count, actor);
|
||||||
|
|
||||||
|
if (!item.getRefData().getCount())
|
||||||
|
{
|
||||||
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
|
||||||
{
|
{
|
||||||
if (mSlots[slot] == end())
|
if (mSlots[slot] == end())
|
||||||
|
@ -469,13 +473,11 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
|
||||||
|
|
||||||
if (*mSlots[slot] == item)
|
if (*mSlots[slot] == item)
|
||||||
{
|
{
|
||||||
// restacking is disabled cause it may break removal
|
unequipSlot(slot, actor);
|
||||||
unequipSlot(slot, actor, false);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
int retCount = ContainerStore::remove(item, count, actor);
|
|
||||||
|
|
||||||
// If an armor/clothing item is removed, try to find a replacement,
|
// If an armor/clothing item is removed, try to find a replacement,
|
||||||
// but not for the player nor werewolves.
|
// but not for the player nor werewolves.
|
||||||
|
@ -500,9 +502,9 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
|
||||||
return retCount;
|
return retCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, const MWWorld::Ptr& actor, bool restack)
|
MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, const MWWorld::Ptr& actor)
|
||||||
{
|
{
|
||||||
ContainerStoreIterator it = getSlot(slot);
|
ContainerStoreIterator it = mSlots[slot];
|
||||||
|
|
||||||
if (it != end())
|
if (it != end())
|
||||||
{
|
{
|
||||||
|
@ -511,8 +513,7 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c
|
||||||
// empty this slot
|
// empty this slot
|
||||||
mSlots[slot] = end();
|
mSlots[slot] = end();
|
||||||
|
|
||||||
if (restack) {
|
// restack the previously equipped item with other (non-equipped) items
|
||||||
// restack item previously in this slot
|
|
||||||
for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter)
|
for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter)
|
||||||
{
|
{
|
||||||
if (stacks(*iter, *it))
|
if (stacks(*iter, *it))
|
||||||
|
@ -523,7 +524,6 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (actor.getRefData().getHandle() == "player")
|
if (actor.getRefData().getHandle() == "player")
|
||||||
{
|
{
|
||||||
|
|
|
@ -168,12 +168,10 @@ namespace MWWorld
|
||||||
///
|
///
|
||||||
/// @return the number of items actually removed
|
/// @return the number of items actually removed
|
||||||
|
|
||||||
ContainerStoreIterator unequipSlot(int slot, const Ptr& actor, bool restack = true);
|
ContainerStoreIterator unequipSlot(int slot, const Ptr& actor);
|
||||||
///< Unequip \a slot.
|
///< Unequip \a slot.
|
||||||
///
|
///
|
||||||
/// @return an iterator to the item that was previously in the slot
|
/// @return an iterator to the item that was previously in the slot
|
||||||
/// (if \a restack is true, the item can be re-stacked so its count
|
|
||||||
/// may differ from when it was equipped).
|
|
||||||
|
|
||||||
ContainerStoreIterator unequipItem(const Ptr& item, const Ptr& actor);
|
ContainerStoreIterator unequipItem(const Ptr& item, const Ptr& actor);
|
||||||
///< Unequip an item identified by its Ptr. An exception is thrown
|
///< Unequip an item identified by its Ptr. An exception is thrown
|
||||||
|
|
Loading…
Reference in a new issue