|
|
@ -296,7 +296,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
|
|
|
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
|
|
|
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
|
|
|
if (!mPtr.getClass().isBipedal(mPtr))
|
|
|
|
weap = sWeaponTypeListEnd;
|
|
|
|
weap = sWeaponTypeListEnd;
|
|
|
|
|
|
|
|
|
|
|
|
if(force || idle != mIdleState)
|
|
|
|
if(force || idle != mIdleState)
|
|
|
@ -870,10 +870,26 @@ bool CharacterController::updateWeaponState()
|
|
|
|
const MWWorld::Class &cls = mPtr.getClass();
|
|
|
|
const MWWorld::Class &cls = mPtr.getClass();
|
|
|
|
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
|
|
|
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
|
|
|
WeaponType weaptype = WeapType_None;
|
|
|
|
WeaponType weaptype = WeapType_None;
|
|
|
|
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
|
|
|
if(stats.getDrawState() == DrawState_Weapon)
|
|
|
|
MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
|
|
|
|
weaptype = WeapType_HandToHand;
|
|
|
|
|
|
|
|
else if (stats.getDrawState() == DrawState_Spell)
|
|
|
|
|
|
|
|
weaptype = WeapType_Spell;
|
|
|
|
|
|
|
|
|
|
|
|
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
|
|
|
|
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string soundid;
|
|
|
|
|
|
|
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
|
|
|
|
|
|
|
MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
|
|
|
|
|
|
|
|
if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
soundid = (weaptype == WeapType_None) ?
|
|
|
|
|
|
|
|
weapon->getClass().getDownSoundId(*weapon) :
|
|
|
|
|
|
|
|
weapon->getClass().getUpSoundId(*weapon);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool forcestateupdate = false;
|
|
|
|
bool forcestateupdate = false;
|
|
|
|
if(weaptype != mWeaponType && mHitState != CharState_KnockDown)
|
|
|
|
if(weaptype != mWeaponType && mHitState != CharState_KnockDown)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -913,16 +929,10 @@ bool CharacterController::updateWeaponState()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(weapon != inv.end() && !(weaptype == WeapType_None && mWeaponType == WeapType_Spell))
|
|
|
|
if(!soundid.empty())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::string soundid = (weaptype == WeapType_None) ?
|
|
|
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
|
|
|
weapon->getClass().getDownSoundId(*weapon) :
|
|
|
|
sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f);
|
|
|
|
weapon->getClass().getUpSoundId(*weapon);
|
|
|
|
|
|
|
|
if(!soundid.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
|
|
|
|
|
|
|
sndMgr->playSound3D(mPtr, soundid, 1.0f, 1.0f);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
mWeaponType = weaptype;
|
|
|
|
mWeaponType = weaptype;
|
|
|
@ -945,22 +955,28 @@ bool CharacterController::updateWeaponState()
|
|
|
|
sndMgr->stopSound3D(mPtr, "WolfRun");
|
|
|
|
sndMgr->stopSound3D(mPtr, "WolfRun");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name());
|
|
|
|
|
|
|
|
float weapSpeed = 1.0f;
|
|
|
|
|
|
|
|
if(isWeapon)
|
|
|
|
|
|
|
|
weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Cancel attack if we no longer have ammunition
|
|
|
|
// Cancel attack if we no longer have ammunition
|
|
|
|
bool ammunition = true;
|
|
|
|
bool ammunition = true;
|
|
|
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
|
|
|
bool isWeapon = false;
|
|
|
|
if (mWeaponType == WeapType_Crossbow)
|
|
|
|
float weapSpeed = 1.f;
|
|
|
|
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt);
|
|
|
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
|
|
|
else if (mWeaponType == WeapType_BowAndArrow)
|
|
|
|
|
|
|
|
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow);
|
|
|
|
|
|
|
|
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
mAnimation->disable(mCurrentWeapon);
|
|
|
|
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
|
|
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
|
|
|
MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
|
|
|
|
|
|
|
|
isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name());
|
|
|
|
|
|
|
|
if(isWeapon)
|
|
|
|
|
|
|
|
weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
|
|
|
|
|
|
|
if (mWeaponType == WeapType_Crossbow)
|
|
|
|
|
|
|
|
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt);
|
|
|
|
|
|
|
|
else if (mWeaponType == WeapType_BowAndArrow)
|
|
|
|
|
|
|
|
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow);
|
|
|
|
|
|
|
|
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mAnimation->disable(mCurrentWeapon);
|
|
|
|
|
|
|
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float complete;
|
|
|
|
float complete;
|
|
|
@ -1001,15 +1017,14 @@ bool CharacterController::updateWeaponState()
|
|
|
|
|
|
|
|
|
|
|
|
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
|
|
|
|
const ESM::Static* castStatic = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>().find ("VFX_Hands");
|
|
|
|
if (mAnimation->getNode("Left Hand"))
|
|
|
|
if (mAnimation->getNode("Left Hand"))
|
|
|
|
{
|
|
|
|
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle);
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle);
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 L Hand", effect->mParticle);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mAnimation->getNode("Right Hand"))
|
|
|
|
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle);
|
|
|
|
|
|
|
|
else
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle);
|
|
|
|
mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Bip01 R Hand", effect->mParticle);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch(effectentry.mRange)
|
|
|
|
switch(effectentry.mRange)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1024,14 +1039,20 @@ bool CharacterController::updateWeaponState()
|
|
|
|
0.0f, 0);
|
|
|
|
0.0f, 0);
|
|
|
|
mUpperBodyState = UpperCharState_CastingSpell;
|
|
|
|
mUpperBodyState = UpperCharState_CastingSpell;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (inv.getSelectedEnchantItem() != inv.end())
|
|
|
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Enchanted items cast immediately (no animation)
|
|
|
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
|
|
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
|
|
|
if (inv.getSelectedEnchantItem() != inv.end())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Enchanted items cast immediately (no animation)
|
|
|
|
|
|
|
|
MWBase::Environment::get().getWorld()->castSpell(mPtr);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(mWeaponType == WeapType_PickProbe)
|
|
|
|
else if(mWeaponType == WeapType_PickProbe)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
|
|
MWWorld::Ptr item = *weapon;
|
|
|
|
MWWorld::Ptr item = *weapon;
|
|
|
|
// TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes.
|
|
|
|
// TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes.
|
|
|
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
|
|
|
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
|
|
|
@ -1063,7 +1084,10 @@ bool CharacterController::updateWeaponState()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(isWeapon && mPtr.getRefData().getHandle() == "player" &&
|
|
|
|
if(isWeapon && mPtr.getRefData().getHandle() == "player" &&
|
|
|
|
Settings::Manager::getBool("best attack", "Game"))
|
|
|
|
Settings::Manager::getBool("best attack", "Game"))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
|
|
|
mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
|
|
|
|
mAttackType = getBestAttack(weapon->get<ESM::Weapon>()->mBase);
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
determineAttackType();
|
|
|
|
determineAttackType();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1283,17 +1307,21 @@ bool CharacterController::updateWeaponState()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
|
|
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
|
|
|
if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()
|
|
|
|
|
|
|
|
&& updateCarriedLeftVisible(mWeaponType))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm,
|
|
|
|
MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
|
|
|
false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true);
|
|
|
|
MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
|
|
|
|
}
|
|
|
|
if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name()
|
|
|
|
else if (mAnimation->isPlaying("torch"))
|
|
|
|
&& updateCarriedLeftVisible(mWeaponType))
|
|
|
|
{
|
|
|
|
|
|
|
|
mAnimation->disable("torch");
|
|
|
|
{
|
|
|
|
|
|
|
|
mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm,
|
|
|
|
|
|
|
|
false, 1.0f, "start", "stop", 0.0f, (~(size_t)0), true);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (mAnimation->isPlaying("torch"))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mAnimation->disable("torch");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return forcestateupdate;
|
|
|
|
return forcestateupdate;
|
|
|
@ -1607,7 +1635,7 @@ void CharacterController::update(float duration)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(cls.hasInventoryStore(mPtr))
|
|
|
|
if(cls.isBipedal(mPtr))
|
|
|
|
forcestateupdate = updateWeaponState() || forcestateupdate;
|
|
|
|
forcestateupdate = updateWeaponState() || forcestateupdate;
|
|
|
|
else
|
|
|
|
else
|
|
|
|
forcestateupdate = updateCreatureState() || forcestateupdate;
|
|
|
|
forcestateupdate = updateCreatureState() || forcestateupdate;
|
|
|
@ -1839,15 +1867,12 @@ void CharacterController::determineAttackType()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
|
|
|
|
float *move = mPtr.getClass().getMovementSettings(mPtr).mPosition;
|
|
|
|
|
|
|
|
|
|
|
|
if(mPtr.getClass().hasInventoryStore(mPtr))
|
|
|
|
if (move[1] && !move[0]) // forward-backward
|
|
|
|
{
|
|
|
|
mAttackType = "thrust";
|
|
|
|
if (move[1] && !move[0]) // forward-backward
|
|
|
|
else if (move[0] && !move[1]) //sideway
|
|
|
|
mAttackType = "thrust";
|
|
|
|
mAttackType = "slash";
|
|
|
|
else if (move[0] && !move[1]) //sideway
|
|
|
|
else
|
|
|
|
mAttackType = "slash";
|
|
|
|
mAttackType = "chop";
|
|
|
|
else
|
|
|
|
|
|
|
|
mAttackType = "chop";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CharacterController::isReadyToBlock() const
|
|
|
|
bool CharacterController::isReadyToBlock() const
|
|
|
|