mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-30 20:45:33 +00:00
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_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…
Reference in a new issue