1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 21:40:03 +00:00

Merge branch 'nooneactuallyknowshowmorrowindcombatworks' into 'master'

Check if the victim is within weapon reach upon hit (#8280)

See merge request OpenMW/openmw!4518
This commit is contained in:
psi29a 2025-01-18 10:40:52 +00:00
commit c16064e6f3
4 changed files with 34 additions and 11 deletions

View File

@ -236,11 +236,8 @@ namespace MWClass
}
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting>& store = world->getStore().get<ESM::GameSetting>();
float dist = store.find("fCombatDistance")->mValue.getFloat();
if (!weapon.isEmpty())
dist *= weapon.get<ESM::Weapon>()->mBase->mData.mReach;
const float dist = MWMechanics::getMeleeWeaponReach(ptr, weapon);
const std::pair<MWWorld::Ptr, osg::Vec3f> result = MWMechanics::getHitContact(ptr, dist);
if (result.first.isEmpty()) // Didn't hit anything
return true;
@ -281,6 +278,9 @@ namespace MWClass
if (otherstats.isDead()) // Can't hit dead actors
return;
if (!MWMechanics::isInMeleeReach(ptr, victim, MWMechanics::getMeleeWeaponReach(ptr, weapon)))
return;
if (!success)
{
victim.getClass().onHit(

View File

@ -572,12 +572,8 @@ namespace MWClass
weapon = *weaponslot;
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting>& store = world->getStore().get<ESM::GameSetting>();
const float fCombatDistance = store.find("fCombatDistance")->mValue.getFloat();
float dist = fCombatDistance
* (!weapon.isEmpty() ? weapon.get<ESM::Weapon>()->mBase->mData.mReach
: store.find("fHandToHandReach")->mValue.getFloat());
const float dist = MWMechanics::getMeleeWeaponReach(ptr, weapon);
const std::pair<MWWorld::Ptr, osg::Vec3f> result = MWMechanics::getHitContact(ptr, dist);
if (result.first.isEmpty()) // Didn't hit anything
return true;
@ -615,6 +611,9 @@ namespace MWClass
if (otherstats.isDead()) // Can't hit dead actors
return;
if (!MWMechanics::isInMeleeReach(ptr, victim, MWMechanics::getMeleeWeaponReach(ptr, weapon)))
return;
if (ptr == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->setEnemy(victim);

View File

@ -578,6 +578,24 @@ namespace MWMechanics
return dist;
}
float getMeleeWeaponReach(const MWWorld::Ptr& actor, const MWWorld::Ptr& weapon)
{
MWBase::World* world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting>& store = world->getStore().get<ESM::GameSetting>();
const float fCombatDistance = store.find("fCombatDistance")->mValue.getFloat();
if (!weapon.isEmpty())
return fCombatDistance * weapon.get<ESM::Weapon>()->mBase->mData.mReach;
if (actor.getClass().isNpc())
return fCombatDistance * store.find("fHandToHandReach")->mValue.getFloat();
return fCombatDistance;
}
bool isInMeleeReach(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const float reach)
{
const float heightDiff = actor.getRefData().getPosition().pos[2] - target.getRefData().getPosition().pos[2];
return std::abs(heightDiff) < reach && getDistanceToBounds(actor, target) < reach;
}
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::Ptr& actor, float reach)
{
// Lasciate ogne speranza, voi ch'entrate
@ -614,11 +632,13 @@ namespace MWMechanics
{
if (actor == target || target.getClass().getCreatureStats(target).isDead())
continue;
const float dist = getDistanceToBounds(actor, target);
const osg::Vec3f targetPos(target.getRefData().getPosition().asVec3());
if (dist >= reach || dist >= minDist || std::abs(targetPos.z() - actorPos.z()) >= reach)
if (dist >= minDist || !isInMeleeReach(actor, target, reach))
continue;
const osg::Vec3f targetPos(target.getRefData().getPosition().asVec3());
// Horizontal angle checks.
osg::Vec2f actorToTargetXY{ targetPos.x() - actorPos.x(), targetPos.y() - actorPos.y() };
actorToTargetXY.normalize();

View File

@ -64,6 +64,10 @@ namespace MWMechanics
// Cursed distance calculation used for combat proximity and hit checks in Morrowind
float getDistanceToBounds(const MWWorld::Ptr& actor, const MWWorld::Ptr& target);
float getMeleeWeaponReach(const MWWorld::Ptr& actor, const MWWorld::Ptr& weapon);
bool isInMeleeReach(const MWWorld::Ptr& actor, const MWWorld::Ptr& target, const float reach);
// Similarly cursed hit target selection
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(const MWWorld::Ptr& actor, float reach);