mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-28 23:36:42 +00:00
Feature #50: Implement marksman mechanics.
This commit is contained in:
parent
12de0afb03
commit
072dc6d438
7 changed files with 171 additions and 37 deletions
|
@ -7,6 +7,7 @@
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/magiceffects.hpp"
|
#include "../mwmechanics/magiceffects.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
#include "../mwmechanics/disease.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
|
@ -243,15 +244,7 @@ namespace MWClass
|
||||||
|
|
||||||
Ogre::Vector3 hitPosition = result.second;
|
Ogre::Vector3 hitPosition = result.second;
|
||||||
|
|
||||||
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
float hitchance = MWMechanics::getHitChance(ptr, victim, ref->mBase->mData.mCombat);
|
||||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
|
||||||
float hitchance = ref->mBase->mData.mCombat +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
|
||||||
hitchance *= stats.getFatigueTerm();
|
|
||||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
|
||||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
|
||||||
hitchance -= otherstats.getEvasion();
|
|
||||||
|
|
||||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||||
{
|
{
|
||||||
|
@ -334,6 +327,8 @@ namespace MWClass
|
||||||
if (damage > 0)
|
if (damage > 0)
|
||||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
||||||
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
victim.getClass().onHit(victim, damage, true, weapon, ptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -498,15 +498,7 @@ namespace MWClass
|
||||||
if(!weapon.isEmpty())
|
if(!weapon.isEmpty())
|
||||||
weapskill = get(weapon).getEquipmentSkill(weapon);
|
weapskill = get(weapon).getEquipmentSkill(weapon);
|
||||||
|
|
||||||
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
|
||||||
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
|
||||||
float hitchance = stats.getSkill(weapskill).getModified() +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
|
||||||
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
|
||||||
hitchance *= stats.getFatigueTerm();
|
|
||||||
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
|
||||||
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
|
||||||
hitchance -= otherstats.getEvasion();
|
|
||||||
|
|
||||||
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
if((::rand()/(RAND_MAX+1.0)) > hitchance/100.0f)
|
||||||
{
|
{
|
||||||
|
@ -516,6 +508,7 @@ namespace MWClass
|
||||||
|
|
||||||
bool healthdmg;
|
bool healthdmg;
|
||||||
float damage = 0.0f;
|
float damage = 0.0f;
|
||||||
|
MWMechanics::NpcStats &stats = getNpcStats(ptr);
|
||||||
if(!weapon.isEmpty())
|
if(!weapon.isEmpty())
|
||||||
{
|
{
|
||||||
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
const bool weaphashealth = get(weapon).hasItemHealth(weapon);
|
||||||
|
@ -615,6 +608,8 @@ namespace MWClass
|
||||||
if (healthdmg && damage > 0)
|
if (healthdmg && damage > 0)
|
||||||
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
||||||
|
MWMechanics::diseaseContact(victim, ptr);
|
||||||
|
|
||||||
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
othercls.onHit(victim, damage, healthdmg, weapon, ptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,9 +643,6 @@ namespace MWClass
|
||||||
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
ptr.getRefData().getLocals().setVarByInt(script, "onpchitme", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attacker.isEmpty())
|
|
||||||
MWMechanics::diseaseContact(ptr, attacker);
|
|
||||||
|
|
||||||
if (damage > 0.0f && !object.isEmpty())
|
if (damage > 0.0f && !object.isEmpty())
|
||||||
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
MWMechanics::resistNormalWeapon(ptr, attacker, object, damage);
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,12 @@
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/soundmanager.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/movement.hpp"
|
#include "../mwmechanics/movement.hpp"
|
||||||
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
@ -17,14 +20,30 @@
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 n)
|
Ogre::Radian signedAngle(Ogre::Vector3 v1, Ogre::Vector3 v2, Ogre::Vector3 normal)
|
||||||
{
|
{
|
||||||
return Ogre::Math::ATan2(
|
return Ogre::Math::ATan2(
|
||||||
n.dotProduct( v1.crossProduct(v2) ),
|
normal.dotProduct( v1.crossProduct(v2) ),
|
||||||
v1.dotProduct(v2)
|
v1.dotProduct(v2)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void applyEnchantment (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, const MWWorld::Ptr& object, const Ogre::Vector3& hitPosition)
|
||||||
|
{
|
||||||
|
std::string enchantmentName = !object.isEmpty() ? object.getClass().getEnchantment(object) : "";
|
||||||
|
if (!enchantmentName.empty())
|
||||||
|
{
|
||||||
|
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(
|
||||||
|
enchantmentName);
|
||||||
|
if (enchantment->mData.mType == ESM::Enchantment::WhenStrikes)
|
||||||
|
{
|
||||||
|
MWMechanics::CastSpell cast(attacker, victim);
|
||||||
|
cast.mHitPosition = hitPosition;
|
||||||
|
cast.cast(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
|
@ -135,4 +154,94 @@ namespace MWMechanics
|
||||||
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicTargetResistsWeapons}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile,
|
||||||
|
const Ogre::Vector3& hitPosition)
|
||||||
|
{
|
||||||
|
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||||
|
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
MWMechanics::CreatureStats& attackerStats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
|
||||||
|
const MWWorld::Class &othercls = victim.getClass();
|
||||||
|
if(!othercls.isActor()) // Can't hit non-actors
|
||||||
|
return;
|
||||||
|
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
|
||||||
|
if(otherstats.isDead()) // Can't hit dead actors
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(attacker.getRefData().getHandle() == "player")
|
||||||
|
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
|
||||||
|
|
||||||
|
int weapskill = ESM::Skill::Marksman;
|
||||||
|
if(!weapon.isEmpty())
|
||||||
|
weapskill = weapon.getClass().getEquipmentSkill(weapon);
|
||||||
|
|
||||||
|
float skillValue = attacker.getClass().getSkill(attacker,
|
||||||
|
weapon.getClass().getEquipmentSkill(weapon));
|
||||||
|
|
||||||
|
if((::rand()/(RAND_MAX+1.0)) > getHitChance(attacker, victim, skillValue)/100.0f)
|
||||||
|
{
|
||||||
|
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float damage = 0.0f;
|
||||||
|
|
||||||
|
float fDamageStrengthBase = gmst.find("fDamageStrengthBase")->getFloat();
|
||||||
|
float fDamageStrengthMult = gmst.find("fDamageStrengthMult")->getFloat();
|
||||||
|
|
||||||
|
const unsigned char* attack = weapon.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||||
|
damage = attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength()); // Bow/crossbow damage
|
||||||
|
if (weapon != projectile)
|
||||||
|
{
|
||||||
|
// Arrow/bolt damage
|
||||||
|
attack = projectile.get<ESM::Weapon>()->mBase->mData.mChop;
|
||||||
|
damage += attack[0] + ((attack[1]-attack[0])*attackerStats.getAttackStrength());
|
||||||
|
}
|
||||||
|
|
||||||
|
damage *= fDamageStrengthBase +
|
||||||
|
(attackerStats.getAttribute(ESM::Attribute::Strength).getModified() * fDamageStrengthMult * 0.1);
|
||||||
|
|
||||||
|
if(attacker.getRefData().getHandle() == "player")
|
||||||
|
attacker.getClass().skillUsageSucceeded(attacker, weapskill, 0);
|
||||||
|
|
||||||
|
bool detected = MWBase::Environment::get().getMechanicsManager()->awarenessCheck(attacker, victim);
|
||||||
|
if(!detected)
|
||||||
|
{
|
||||||
|
damage *= gmst.find("fCombatCriticalStrikeMult")->getFloat();
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sTargetCriticalStrike}");
|
||||||
|
MWBase::Environment::get().getSoundManager()->playSound3D(victim, "critical damage", 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
if (victim.getClass().getCreatureStats(victim).getKnockedDown())
|
||||||
|
damage *= gmst.find("fCombatKODamageMult")->getFloat();
|
||||||
|
|
||||||
|
// Apply "On hit" effect of the weapon
|
||||||
|
applyEnchantment(attacker, victim, weapon, hitPosition);
|
||||||
|
if (weapon != projectile)
|
||||||
|
applyEnchantment(attacker, victim, projectile, hitPosition);
|
||||||
|
|
||||||
|
if (damage > 0)
|
||||||
|
MWBase::Environment::get().getWorld()->spawnBloodEffect(victim, hitPosition);
|
||||||
|
|
||||||
|
float fProjectileThrownStoreChance = gmst.find("fProjectileThrownStoreChance")->getFloat();
|
||||||
|
if ((::rand()/(RAND_MAX+1.0)) < fProjectileThrownStoreChance/100.f)
|
||||||
|
victim.getClass().getContainerStore(victim).add(projectile, 1, victim);
|
||||||
|
|
||||||
|
victim.getClass().onHit(victim, damage, true, projectile, attacker, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
float getHitChance(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, int skillValue)
|
||||||
|
{
|
||||||
|
MWMechanics::CreatureStats &stats = attacker.getClass().getCreatureStats(attacker);
|
||||||
|
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
|
||||||
|
float hitchance = skillValue +
|
||||||
|
(stats.getAttribute(ESM::Attribute::Agility).getModified() / 5.0f) +
|
||||||
|
(stats.getAttribute(ESM::Attribute::Luck).getModified() / 10.0f);
|
||||||
|
hitchance *= stats.getFatigueTerm();
|
||||||
|
hitchance += mageffects.get(ESM::MagicEffect::FortifyAttack).mMagnitude -
|
||||||
|
mageffects.get(ESM::MagicEffect::Blind).mMagnitude;
|
||||||
|
hitchance -= victim.getClass().getCreatureStats(victim).getEvasion();
|
||||||
|
return hitchance;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define OPENMW_MECHANICS_COMBAT_H
|
#define OPENMW_MECHANICS_COMBAT_H
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
#include <OgreVector3.h>
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -11,6 +12,13 @@ bool blockMeleeAttack (const MWWorld::Ptr& attacker, const MWWorld::Ptr& blocker
|
||||||
|
|
||||||
void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage);
|
void resistNormalWeapon (const MWWorld::Ptr& actor, const MWWorld::Ptr& attacker, const MWWorld::Ptr& weapon, float& damage);
|
||||||
|
|
||||||
|
/// @note for a thrown weapon, \a weapon == \a projectile, for bows/crossbows, \a projectile is the arrow/bolt
|
||||||
|
void projectileHit (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, MWWorld::Ptr weapon, const MWWorld::Ptr& projectile,
|
||||||
|
const Ogre::Vector3& hitPosition);
|
||||||
|
|
||||||
|
/// Get the chance (in percent) for \a attacker to successfully hit \a victim with a given weapon skill value
|
||||||
|
float getHitChance (const MWWorld::Ptr& attacker, const MWWorld::Ptr& victim, int skillValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -779,6 +779,23 @@ void NpcAnimation::releaseArrow()
|
||||||
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
||||||
Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
|
Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
|
||||||
|
|
||||||
|
const MWWorld::Store<ESM::GameSetting> &gmst =
|
||||||
|
MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
|
// Reduce fatigue
|
||||||
|
// somewhat of a guess, but using the weapon weight makes sense
|
||||||
|
const float fFatigueAttackBase = gmst.find("fFatigueAttackBase")->getFloat();
|
||||||
|
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
|
||||||
|
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||||
|
MWMechanics::CreatureStats& attackerStats = mPtr.getClass().getCreatureStats(mPtr);
|
||||||
|
MWMechanics::DynamicStat<float> fatigue = attackerStats.getFatigue();
|
||||||
|
const float normalizedEncumbrance = mPtr.getClass().getEncumbrance(mPtr) / mPtr.getClass().getCapacity(mPtr);
|
||||||
|
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||||
|
if (!weapon->isEmpty())
|
||||||
|
fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult;
|
||||||
|
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss);
|
||||||
|
attackerStats.setFatigue(fatigue);
|
||||||
|
|
||||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||||
{
|
{
|
||||||
// Thrown weapons get detached now
|
// Thrown weapons get detached now
|
||||||
|
@ -795,7 +812,12 @@ void NpcAnimation::releaseArrow()
|
||||||
launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition();
|
launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *weapon, launchPos, orient, *weapon, 400);
|
float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->getFloat();
|
||||||
|
float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->getFloat();
|
||||||
|
float speed = fThrownWeaponMinSpeed + (fThrownWeaponMaxSpeed - fThrownWeaponMinSpeed) *
|
||||||
|
mPtr.getClass().getCreatureStats(mPtr).getAttackStrength();
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *weapon, launchPos, orient, *weapon, speed);
|
||||||
|
|
||||||
showWeapons(false);
|
showWeapons(false);
|
||||||
|
|
||||||
|
@ -819,8 +841,11 @@ void NpcAnimation::releaseArrow()
|
||||||
launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition();
|
launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \todo speed
|
float fProjectileMinSpeed = gmst.find("fProjectileMinSpeed")->getFloat();
|
||||||
MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *ammo, launchPos, orient, *weapon, 400);
|
float fProjectileMaxSpeed = gmst.find("fProjectileMaxSpeed")->getFloat();
|
||||||
|
float speed = fProjectileMinSpeed + (fProjectileMaxSpeed - fProjectileMinSpeed) * mPtr.getClass().getCreatureStats(mPtr).getAttackStrength();
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *ammo, launchPos, orient, *weapon, speed);
|
||||||
|
|
||||||
inv.remove(*ammo, 1, mPtr);
|
inv.remove(*ammo, 1, mPtr);
|
||||||
mAmmunition.setNull();
|
mAmmunition.setNull();
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/levelledlist.hpp"
|
#include "../mwmechanics/levelledlist.hpp"
|
||||||
|
#include "../mwmechanics/combat.hpp"
|
||||||
|
|
||||||
#include "../mwrender/sky.hpp"
|
#include "../mwrender/sky.hpp"
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
@ -2141,7 +2141,7 @@ namespace MWWorld
|
||||||
ProjectileState state;
|
ProjectileState state;
|
||||||
state.mActorHandle = actor.getRefData().getHandle();
|
state.mActorHandle = actor.getRefData().getHandle();
|
||||||
state.mBow = bow;
|
state.mBow = bow;
|
||||||
state.mSpeed = speed;
|
state.mVelocity = orient.yAxis() * speed;
|
||||||
|
|
||||||
MWWorld::ManualRef ref(getStore(), projectile.getCellRef().mRefID);
|
MWWorld::ManualRef ref(getStore(), projectile.getCellRef().mRefID);
|
||||||
|
|
||||||
|
@ -2258,14 +2258,19 @@ namespace MWWorld
|
||||||
|
|
||||||
MWWorld::Ptr ptr = it->first;
|
MWWorld::Ptr ptr = it->first;
|
||||||
|
|
||||||
Ogre::Quaternion orient = ptr.getRefData().getBaseNode()->getOrientation();
|
// gravity constant - must be way lower than the gravity affecting actors, since we're not
|
||||||
|
// simulating aerodynamics at all
|
||||||
|
it->second.mVelocity -= Ogre::Vector3(0, 0, 627.2f * 0.1f) * duration;
|
||||||
|
|
||||||
float speed = it->second.mSpeed;
|
|
||||||
|
|
||||||
Ogre::Vector3 direction = orient.yAxis();
|
|
||||||
direction.normalise();
|
|
||||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||||
Ogre::Vector3 newPos = pos + direction * duration * speed;
|
Ogre::Vector3 newPos = pos + it->second.mVelocity * duration;
|
||||||
|
|
||||||
|
Ogre::Quaternion orient = Ogre::Vector3::UNIT_Y.getRotationTo(it->second.mVelocity);
|
||||||
|
Ogre::Matrix3 mat;
|
||||||
|
orient.ToRotationMatrix(mat);
|
||||||
|
Ogre::Radian xr,yr,zr;
|
||||||
|
mat.ToEulerAnglesXYZ(xr, yr, zr);
|
||||||
|
rotateObject(ptr, -xr.valueDegrees(), -yr.valueDegrees(), -zr.valueDegrees());
|
||||||
|
|
||||||
// Check for impact
|
// Check for impact
|
||||||
btVector3 from(pos.x, pos.y, pos.z);
|
btVector3 from(pos.x, pos.y, pos.z);
|
||||||
|
@ -2300,13 +2305,13 @@ namespace MWWorld
|
||||||
}
|
}
|
||||||
else if (obstacle.getClass().isActor())
|
else if (obstacle.getClass().isActor())
|
||||||
{
|
{
|
||||||
// Fargoth
|
MWMechanics::projectileHit(caster, obstacle, it->second.mBow, ptr, pos + (newPos - pos) * cIt->first);
|
||||||
obstacle.getClass().getCreatureStats(obstacle).setHealth(0);
|
|
||||||
}
|
}
|
||||||
hit = true;
|
hit = true;
|
||||||
}
|
}
|
||||||
if (hit)
|
if (hit)
|
||||||
{
|
{
|
||||||
|
deleteObject(ptr);
|
||||||
mProjectiles.erase(it++);
|
mProjectiles.erase(it++);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ namespace MWWorld
|
||||||
|
|
||||||
MWWorld::Ptr mBow; // bow or crossbow the projectile was fired from
|
MWWorld::Ptr mBow; // bow or crossbow the projectile was fired from
|
||||||
|
|
||||||
float mSpeed;
|
Ogre::Vector3 mVelocity;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
|
std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
|
||||||
|
|
Loading…
Reference in a new issue