mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-04 02:41:19 +00:00
103 lines
3.1 KiB
C++
103 lines
3.1 KiB
C++
#include "aicast.hpp"
|
|
|
|
#include <components/misc/constants.hpp>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/mechanicsmanager.hpp"
|
|
#include "../mwbase/world.hpp"
|
|
|
|
#include "../mwworld/class.hpp"
|
|
|
|
#include "aicombataction.hpp"
|
|
#include "character.hpp"
|
|
#include "steering.hpp"
|
|
|
|
namespace MWMechanics
|
|
{
|
|
namespace
|
|
{
|
|
float getInitialDistance(const ESM::RefId& spellId)
|
|
{
|
|
ActionSpell action = ActionSpell(spellId);
|
|
bool isRanged;
|
|
return action.getCombatRange(isRanged);
|
|
}
|
|
}
|
|
}
|
|
|
|
MWMechanics::AiCast::AiCast(const ESM::RefId& targetId, const ESM::RefId& spellId, bool scriptedSpell)
|
|
: mTargetId(targetId)
|
|
, mSpellId(spellId)
|
|
, mCasting(false)
|
|
, mScripted(scriptedSpell)
|
|
, mDistance(getInitialDistance(spellId))
|
|
{
|
|
}
|
|
|
|
bool MWMechanics::AiCast::execute(const MWWorld::Ptr& actor, MWMechanics::CharacterController& characterController,
|
|
MWMechanics::AiState& state, float duration)
|
|
{
|
|
MWWorld::Ptr target;
|
|
if (actor.getCellRef().getRefId() == mTargetId)
|
|
{
|
|
// If the target has the same ID as caster, consider that actor casts spell with Self range.
|
|
target = actor;
|
|
}
|
|
else
|
|
{
|
|
target = getTarget();
|
|
if (target.isEmpty())
|
|
return true;
|
|
|
|
if (!mScripted
|
|
&& !pathTo(actor, target.getRefData().getPosition().asVec3(), duration,
|
|
characterController.getSupportedMovementDirections(), mDistance))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
osg::Vec3f targetPos = target.getRefData().getPosition().asVec3();
|
|
// If the target of an on-target spell is an actor that is not the caster
|
|
// the target position must be adjusted so that it's not casted at the actor's feet.
|
|
if (target != actor && target.getClass().isActor())
|
|
{
|
|
osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(target);
|
|
targetPos.z() += halfExtents.z() * 2 * Constants::TorsoHeight;
|
|
}
|
|
|
|
osg::Vec3f actorPos = actor.getRefData().getPosition().asVec3();
|
|
osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
|
actorPos.z() += halfExtents.z() * 2 * Constants::TorsoHeight;
|
|
|
|
osg::Vec3f dir = targetPos - actorPos;
|
|
|
|
bool turned = smoothTurn(actor, getZAngleToDir(dir), 2, osg::DegreesToRadians(3.f));
|
|
turned &= smoothTurn(actor, getXAngleToDir(dir), 0, osg::DegreesToRadians(3.f));
|
|
|
|
if (!turned)
|
|
return false;
|
|
|
|
// Check if the actor is already casting another spell
|
|
bool isCasting = MWBase::Environment::get().getMechanicsManager()->isCastingSpell(actor);
|
|
if (isCasting && !mCasting)
|
|
return false;
|
|
|
|
if (!mCasting)
|
|
{
|
|
MWBase::Environment::get().getMechanicsManager()->castSpell(actor, mSpellId, mScripted);
|
|
mCasting = true;
|
|
return false;
|
|
}
|
|
|
|
// Finish package, if actor finished spellcasting
|
|
return !isCasting;
|
|
}
|
|
|
|
MWWorld::Ptr MWMechanics::AiCast::getTarget() const
|
|
{
|
|
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtr(mTargetId, false);
|
|
|
|
return target;
|
|
}
|