mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 06:53:53 +00:00
Merge branch 'attackontitan' into 'master'
Make the character controller less miserable, round 7: attack animations, round 2 See merge request OpenMW/openmw!2253
This commit is contained in:
commit
d9d7277b0e
1 changed files with 90 additions and 130 deletions
|
@ -1129,9 +1129,10 @@ bool CharacterController::updateWeaponState()
|
|||
|
||||
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
|
||||
|
||||
std::string upSoundId;
|
||||
std::string downSoundId;
|
||||
bool weaponChanged = false;
|
||||
bool ammunition = true;
|
||||
float weapSpeed = 1.f;
|
||||
if (cls.hasInventoryStore(mPtr))
|
||||
{
|
||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
||||
|
@ -1139,23 +1140,55 @@ bool CharacterController::updateWeaponState()
|
|||
if(stats.getDrawState() == DrawState::Spell)
|
||||
weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
if(weapon != inv.end() && mWeaponType != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::Spell && weaptype != ESM::Weapon::None)
|
||||
upSoundId = weapon->getClass().getUpSoundId(*weapon);
|
||||
|
||||
if(weapon != inv.end() && mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None)
|
||||
downSoundId = weapon->getClass().getDownSoundId(*weapon);
|
||||
|
||||
MWWorld::Ptr newWeapon;
|
||||
if (weapon != inv.end())
|
||||
{
|
||||
newWeapon = *weapon;
|
||||
if (isRealWeapon(mWeaponType))
|
||||
downSoundId = newWeapon.getClass().getDownSoundId(newWeapon);
|
||||
}
|
||||
// weapon->HtH switch: weapon is empty already, so we need to take sound from previous weapon
|
||||
if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell)
|
||||
else if (!mWeapon.isEmpty() && weaptype == ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell)
|
||||
downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
|
||||
|
||||
MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
||||
|
||||
if (mWeapon != newWeapon)
|
||||
{
|
||||
mWeapon = newWeapon;
|
||||
weaponChanged = true;
|
||||
}
|
||||
|
||||
if (stats.getDrawState() == DrawState::Weapon && !mWeapon.isEmpty() && mWeapon.getType() == ESM::Weapon::sRecordId)
|
||||
{
|
||||
weapSpeed = mWeapon.get<ESM::Weapon>()->mBase->mData.mSpeed;
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
int ammotype = getWeaponType(mWeapon.get<ESM::Weapon>()->mBase->mData.mType)->mAmmoType;
|
||||
if (ammotype != ESM::Weapon::None)
|
||||
ammunition = ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ammotype;
|
||||
// Cancel attack if we no longer have ammunition
|
||||
if (!ammunition)
|
||||
{
|
||||
if (mUpperBodyState == UpperBodyState::AttackPreWindUp || mUpperBodyState == UpperBodyState::AttackWindUp)
|
||||
{
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
mUpperBodyState = UpperBodyState::WeaponEquipped;
|
||||
}
|
||||
setAttackingOrSpell(false);
|
||||
}
|
||||
}
|
||||
|
||||
MWWorld::ConstContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||
if (torch != inv.end() && torch->getType() == ESM::Light::sRecordId && updateCarriedLeftVisible(mWeaponType))
|
||||
{
|
||||
if (mAnimation->isPlaying("shield"))
|
||||
mAnimation->disable("shield");
|
||||
|
||||
mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm,
|
||||
false, 1.0f, "start", "stop", 0.0f, std::numeric_limits<size_t>::max(), true);
|
||||
}
|
||||
else if (mAnimation->isPlaying("torch"))
|
||||
{
|
||||
mAnimation->disable("torch");
|
||||
}
|
||||
}
|
||||
|
||||
// For biped actors, blend weapon animations with lower body animations with higher priority
|
||||
|
@ -1268,10 +1301,13 @@ bool CharacterController::updateWeaponState()
|
|||
{
|
||||
mAnimation->showWeapons(true);
|
||||
}
|
||||
}
|
||||
if (!upSoundId.empty())
|
||||
{
|
||||
sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f);
|
||||
|
||||
if (!mWeapon.isEmpty() && mWeaponType != ESM::Weapon::HandToHand && isRealWeapon(weaptype))
|
||||
{
|
||||
std::string upSoundId = mWeapon.getClass().getUpSoundId(mWeapon);
|
||||
if (!upSoundId.empty())
|
||||
sndMgr->playSound3D(mPtr, upSoundId, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1287,7 +1323,6 @@ bool CharacterController::updateWeaponState()
|
|||
|
||||
mWeaponType = weaptype;
|
||||
mCurrentWeapon = weapgroup;
|
||||
|
||||
}
|
||||
|
||||
// Make sure that we disabled unequipping animation
|
||||
|
@ -1314,46 +1349,6 @@ bool CharacterController::updateWeaponState()
|
|||
sndMgr->stopSound3D(mPtr, "WolfRun");
|
||||
}
|
||||
|
||||
bool ammunition = true;
|
||||
float weapSpeed = 1.f;
|
||||
if (cls.hasInventoryStore(mPtr))
|
||||
{
|
||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
||||
if (stats.getDrawState() == DrawState::Weapon && !mWeapon.isEmpty() && mWeapon.getType() == ESM::Weapon::sRecordId)
|
||||
{
|
||||
weapSpeed = mWeapon.get<ESM::Weapon>()->mBase->mData.mSpeed;
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
int ammotype = getWeaponType(mWeapon.get<ESM::Weapon>()->mBase->mData.mType)->mAmmoType;
|
||||
if (ammotype != ESM::Weapon::None)
|
||||
ammunition = ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ammotype;
|
||||
}
|
||||
|
||||
// Cancel attack if we no longer have ammunition
|
||||
if (!ammunition)
|
||||
{
|
||||
if (mUpperBodyState == UpperBodyState::AttackPreWindUp || mUpperBodyState == UpperBodyState::AttackWindUp)
|
||||
{
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
mUpperBodyState = UpperBodyState::WeaponEquipped;
|
||||
}
|
||||
setAttackingOrSpell(false);
|
||||
}
|
||||
|
||||
MWWorld::ConstContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
||||
if (torch != inv.end() && torch->getType() == ESM::Light::sRecordId && updateCarriedLeftVisible(mWeaponType))
|
||||
{
|
||||
if (mAnimation->isPlaying("shield"))
|
||||
mAnimation->disable("shield");
|
||||
|
||||
mAnimation->play("torch", Priority_Torch, MWRender::Animation::BlendMask_LeftArm,
|
||||
false, 1.0f, "start", "stop", 0.0f, std::numeric_limits<size_t>::max(), true);
|
||||
}
|
||||
else if (mAnimation->isPlaying("torch"))
|
||||
{
|
||||
mAnimation->disable("torch");
|
||||
}
|
||||
}
|
||||
|
||||
// Combat for actors with persistent animations obviously will be buggy
|
||||
if (isPersistentAnimPlaying())
|
||||
return forcestateupdate;
|
||||
|
@ -1397,17 +1392,14 @@ bool CharacterController::updateWeaponState()
|
|||
spellCastResult = world->startSpellCast(mPtr);
|
||||
mCanCast = spellCastResult == MWWorld::SpellCastState::Success;
|
||||
|
||||
if (spellid.empty())
|
||||
if (spellid.empty() && cls.hasInventoryStore(mPtr))
|
||||
{
|
||||
if (cls.hasInventoryStore(mPtr))
|
||||
MWWorld::InventoryStore& inv = cls.getInventoryStore(mPtr);
|
||||
if (inv.getSelectedEnchantItem() != inv.end())
|
||||
{
|
||||
MWWorld::InventoryStore& inv = cls.getInventoryStore(mPtr);
|
||||
if (inv.getSelectedEnchantItem() != inv.end())
|
||||
{
|
||||
const MWWorld::Ptr& enchantItem = *inv.getSelectedEnchantItem();
|
||||
spellid = enchantItem.getClass().getEnchantment(enchantItem);
|
||||
isMagicItem = true;
|
||||
}
|
||||
const MWWorld::Ptr& enchantItem = *inv.getSelectedEnchantItem();
|
||||
spellid = enchantItem.getClass().getEnchantment(enchantItem);
|
||||
isMagicItem = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1554,8 +1546,8 @@ bool CharacterController::updateWeaponState()
|
|||
}
|
||||
}
|
||||
// else if (mPtr != getPlayer()) use mAttackType set by AiCombat
|
||||
startKey = mAttackType+" start";
|
||||
stopKey = mAttackType+" min attack";
|
||||
startKey = mAttackType + ' ' + startKey;
|
||||
stopKey = mAttackType + " min attack";
|
||||
}
|
||||
|
||||
mAnimation->play(mCurrentWeapon, priorityWeapon,
|
||||
|
@ -1584,18 +1576,6 @@ bool CharacterController::updateWeaponState()
|
|||
if (!animPlaying)
|
||||
animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||
|
||||
if (isKnockedDown())
|
||||
{
|
||||
if (mUpperBodyState > UpperBodyState::WeaponEquipped)
|
||||
{
|
||||
mUpperBodyState = UpperBodyState::WeaponEquipped;
|
||||
if (mWeaponType > ESM::Weapon::None)
|
||||
mAnimation->showWeapons(true);
|
||||
}
|
||||
if (!mCurrentWeapon.empty())
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
}
|
||||
|
||||
if (mUpperBodyState == UpperBodyState::AttackWindUp)
|
||||
{
|
||||
mAttackStrength = complete;
|
||||
|
@ -1627,35 +1607,6 @@ bool CharacterController::updateWeaponState()
|
|||
}
|
||||
}
|
||||
|
||||
mAnimation->setPitchFactor(0.f);
|
||||
if (weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
switch (mUpperBodyState)
|
||||
{
|
||||
case UpperBodyState::AttackPreWindUp:
|
||||
mAnimation->setPitchFactor(complete);
|
||||
break;
|
||||
case UpperBodyState::AttackWindUp:
|
||||
case UpperBodyState::AttackRelease:
|
||||
case UpperBodyState::AttackHit:
|
||||
mAnimation->setPitchFactor(1.f);
|
||||
break;
|
||||
case UpperBodyState::AttackEnd:
|
||||
if (animPlaying)
|
||||
{
|
||||
// technically we do not need a pitch for crossbow reload animation,
|
||||
// but we should avoid abrupt repositioning
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
mAnimation->setPitchFactor(std::max(0.f, 1.f-complete*10.f));
|
||||
else
|
||||
mAnimation->setPitchFactor(1.f-complete);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!animPlaying)
|
||||
{
|
||||
if (mUpperBodyState == UpperBodyState::Equipping ||
|
||||
|
@ -1709,35 +1660,23 @@ bool CharacterController::updateWeaponState()
|
|||
playSwishSound(0.0f);
|
||||
}
|
||||
|
||||
if(mAttackType == "shoot")
|
||||
{
|
||||
start = mAttackType+" min hit";
|
||||
stop = mAttackType+" release";
|
||||
}
|
||||
else
|
||||
{
|
||||
start = mAttackType+" min hit";
|
||||
stop = mAttackType+" hit";
|
||||
}
|
||||
std::string hit = mAttackType == "shoot" ? "release" : "hit";
|
||||
start = mAttackType + " min hit";
|
||||
stop = mAttackType + ' ' + hit;
|
||||
mUpperBodyState = UpperBodyState::AttackHit;
|
||||
break;
|
||||
}
|
||||
case UpperBodyState::AttackHit:
|
||||
if(mAttackType == "shoot")
|
||||
start = "follow start";
|
||||
stop = "follow stop";
|
||||
if (mAttackType != "shoot")
|
||||
{
|
||||
start = mAttackType+" follow start";
|
||||
stop = mAttackType+" follow stop";
|
||||
}
|
||||
else
|
||||
{
|
||||
float str = mAttackStrength;
|
||||
start = mAttackType+((str < 0.5f) ? " small follow start"
|
||||
: (str < 1.0f) ? " medium follow start"
|
||||
: " large follow start");
|
||||
stop = mAttackType+((str < 0.5f) ? " small follow stop"
|
||||
: (str < 1.0f) ? " medium follow stop"
|
||||
: " large follow stop");
|
||||
std::string strength = mAttackStrength < 0.5f ? "small" : mAttackStrength < 1.f ? "medium" : "large";
|
||||
start = strength + ' ' + start;
|
||||
stop = strength + ' ' + stop;
|
||||
}
|
||||
start = mAttackType + ' ' + start;
|
||||
stop = mAttackType + ' ' + stop;
|
||||
mUpperBodyState = UpperBodyState::AttackEnd;
|
||||
break;
|
||||
default:
|
||||
|
@ -1757,6 +1696,27 @@ bool CharacterController::updateWeaponState()
|
|||
mUpperBodyState = UpperBodyState::WeaponEquipped;
|
||||
}
|
||||
|
||||
mAnimation->getInfo(mCurrentWeapon, &complete);
|
||||
|
||||
mAnimation->setPitchFactor(0.f);
|
||||
if (mUpperBodyState > UpperBodyState::WeaponEquipped && (weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown))
|
||||
{
|
||||
mAnimation->setPitchFactor(1.f);
|
||||
|
||||
// A smooth transition can be provided if a pre-wind-up section is defined. Random attack animations never have one.
|
||||
if (mUpperBodyState == UpperBodyState::AttackPreWindUp && !isRandomAttackAnimation(mCurrentWeapon))
|
||||
mAnimation->setPitchFactor(complete);
|
||||
else if (mUpperBodyState == UpperBodyState::AttackEnd)
|
||||
{
|
||||
// technically we do not need a pitch for crossbow reload animation,
|
||||
// but we should avoid abrupt repositioning
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
mAnimation->setPitchFactor(std::max(0.f, 1.f-complete*10.f));
|
||||
else
|
||||
mAnimation->setPitchFactor(1.f-complete);
|
||||
}
|
||||
}
|
||||
|
||||
mAnimation->setAccurateAiming(mUpperBodyState > UpperBodyState::WeaponEquipped);
|
||||
|
||||
return forcestateupdate;
|
||||
|
|
Loading…
Reference in a new issue