Feature #50: Handle attach & release of projectiles

actorid
scrawl 11 years ago
parent 8b8fb931a0
commit ffe19e7a52

@ -836,6 +836,9 @@ bool CharacterController::updateWeaponState()
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
mUpperBodyState == UpperCharState_CastingSpell)
{
if (ammunition && mWeaponType == WeapType_Crossbow)
mAnimation->attachArrow();
mUpperBodyState = UpperCharState_WeapEquiped;
//don't allow to continue playing hit animation on UpperBody after actor had attacked during it
if(mHitState == CharState_Hit)

@ -695,6 +695,12 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
else
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")
MWBase::Environment::get().getWorld()->castSpell(mPtr);

@ -295,7 +295,8 @@ public:
virtual void showWeapons(bool showWeapon);
virtual void showCarriedLeft(bool show) {}
virtual void attachArrow() {}
virtual void releaseArrow() {}
void enableLights(bool enable);
Ogre::AxisAlignedBox getWorldBounds();

@ -696,6 +696,17 @@ void NpcAnimation::showWeapons(bool showWeapon)
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
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
@ -726,6 +737,52 @@ void NpcAnimation::showCarriedLeft(bool show)
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)
{
// During first auto equip, we don't play any sounds.

@ -135,6 +135,11 @@ public:
virtual void showWeapons(bool showWeapon);
virtual void showCarriedLeft(bool showa);
virtual void attachArrow();
virtual void releaseArrow();
NifOgre::ObjectScenePtr mAmmunition;
void setViewMode(ViewMode viewMode);
void updateParts();

@ -462,21 +462,23 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::getSelectedEnchantItem(
int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor)
{
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
if (mSlots[slot] == end())
continue;
int retCount = ContainerStore::remove(item, count, actor);
if (*mSlots[slot] == item)
if (!item.getRefData().getCount())
{
for (int slot=0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
// restacking is disabled cause it may break removal
unequipSlot(slot, actor, false);
break;
if (mSlots[slot] == end())
continue;
if (*mSlots[slot] == item)
{
unequipSlot(slot, actor);
break;
}
}
}
int retCount = ContainerStore::remove(item, count, actor);
// If an armor/clothing item is removed, try to find a replacement,
// but not for the player nor werewolves.
if ((actor.getRefData().getHandle() != "player")
@ -500,9 +502,9 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
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())
{
@ -511,17 +513,15 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::unequipSlot(int slot, c
// empty this slot
mSlots[slot] = end();
if (restack) {
// restack item previously in this slot
for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter)
// restack the previously equipped item with other (non-equipped) items
for (MWWorld::ContainerStoreIterator iter (begin()); iter != end(); ++iter)
{
if (stacks(*iter, *it))
{
if (stacks(*iter, *it))
{
iter->getRefData().setCount(iter->getRefData().getCount() + it->getRefData().getCount());
it->getRefData().setCount(0);
retval = iter;
break;
}
iter->getRefData().setCount(iter->getRefData().getCount() + it->getRefData().getCount());
it->getRefData().setCount(0);
retval = iter;
break;
}
}

@ -168,12 +168,10 @@ namespace MWWorld
///
/// @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.
///
/// @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);
///< Unequip an item identified by its Ptr. An exception is thrown

Loading…
Cancel
Save