1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-03 14:45:37 +00:00

Merge remote-tracking branch 'mrcheko/master'

This commit is contained in:
Marc Zinnschlag 2014-05-26 10:08:40 +02:00
commit f0d0a31a19
4 changed files with 50 additions and 27 deletions

View file

@ -191,6 +191,14 @@ namespace MWMechanics
if (againstPlayer && creatureStats.isHostile()) return; // already fighting against player if (againstPlayer && creatureStats.isHostile()) return; // already fighting against player
// pure water creatures won't try to fight with the target on the ground
// except that creature is already hostile
if ((againstPlayer || !creatureStats.isHostile())
&& ((actor1.getClass().canSwim(actor1) && !actor1.getClass().canWalk(actor1) // pure water creature
&& !MWBase::Environment::get().getWorld()->isSwimming(actor2))
|| (!actor1.getClass().canSwim(actor1) && MWBase::Environment::get().getWorld()->isSwimming(actor2)))) // creature can't swim to target
return;
float fight; float fight;
if (againstPlayer) if (againstPlayer)

View file

@ -53,7 +53,7 @@ namespace
// cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target; // cast up-down ray with some offset from actor position to check for pits/obstacles on the way to target;
// magnitude of pits/obstacles is defined by PATHFIND_Z_REACH // magnitude of pits/obstacles is defined by PATHFIND_Z_REACH
bool checkWayIsClear(const Ogre::Vector3& from, const Ogre::Vector3& to, float offset) bool checkWayIsClear(const Ogre::Vector3& from, const Ogre::Vector3& to, float offsetXY)
{ {
if((to - from).length() >= PATHFIND_CAUTION_DIST || abs(from.z - to.z) <= PATHFIND_Z_REACH) if((to - from).length() >= PATHFIND_CAUTION_DIST || abs(from.z - to.z) <= PATHFIND_Z_REACH)
{ {
@ -61,7 +61,7 @@ namespace
dir.z = 0; dir.z = 0;
dir.normalise(); dir.normalise();
float verticalOffset = 200; // instead of '200' here we want the height of the actor float verticalOffset = 200; // instead of '200' here we want the height of the actor
Ogre::Vector3 _from = from + dir*offset + Ogre::Vector3::UNIT_Z * verticalOffset; Ogre::Vector3 _from = from + dir*offsetXY + Ogre::Vector3::UNIT_Z * verticalOffset;
// cast up-down ray and find height in world space of hit // cast up-down ray and find height in world space of hit
float h = _from.z - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, -Ogre::Vector3::UNIT_Z, verticalOffset + PATHFIND_Z_REACH + 1); float h = _from.z - MWBase::Environment::get().getWorld()->getDistToNearestRayHit(_from, -Ogre::Vector3::UNIT_Z, verticalOffset + PATHFIND_Z_REACH + 1);
@ -149,13 +149,24 @@ namespace MWMechanics
bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) bool AiCombat::execute (const MWWorld::Ptr& actor,float duration)
{ {
//General description //General description
if(actor.getClass().getCreatureStats(actor).isDead()) return true; if(actor.getClass().getCreatureStats(actor).isDead())
return true;
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId); MWWorld::Ptr target = MWBase::Environment::get().getWorld()->searchPtrViaActorId(mTargetActorId);
if(target.getClass().getCreatureStats(target).isDead()) if(target.getClass().getCreatureStats(target).isDead())
return true; return true;
if (!actor.getClass().isNpc() && target == MWBase::Environment::get().getWorld()->getPlayerPtr() &&
(actor.getClass().canSwim(actor) && !actor.getClass().canWalk(actor) // pure water creature
&& !MWBase::Environment::get().getWorld()->isSwimming(target)) // Player moved out of water
|| (!actor.getClass().canSwim(actor) && MWBase::Environment::get().getWorld()->isSwimming(target))) // creature can't swim to Player
{
actor.getClass().getCreatureStats(actor).setHostile(false);
actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false);
return true;
}
//Update every frame //Update every frame
if(mCombatMove) if(mCombatMove)
{ {
@ -327,10 +338,11 @@ namespace MWMechanics
Ogre::Vector3 vActorPos(pos.pos); Ogre::Vector3 vActorPos(pos.pos);
Ogre::Vector3 vTargetPos(target.getRefData().getPosition().pos); Ogre::Vector3 vTargetPos(target.getRefData().getPosition().pos);
Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos; Ogre::Vector3 vDirToTarget = vTargetPos - vActorPos;
float distToTarget = vDirToTarget.length();
bool isStuck = false; bool isStuck = false;
float speed = 0.0f; float speed = 0.0f;
if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = actorCls.getSpeed(actor)) / 10.0f) if(mMovement.mPosition[1] && (Ogre::Vector3(mLastPos.pos) - vActorPos).length() < (speed = actorCls.getSpeed(actor)) * tReaction / 2)
isStuck = true; isStuck = true;
mLastPos = pos; mLastPos = pos;
@ -342,16 +354,15 @@ namespace MWMechanics
// determine vertical angle to target // determine vertical angle to target
// if actor can move along z-axis it will control movement dir // if actor can move along z-axis it will control movement dir
// if can't - it will control correct aiming // if can't - it will control correct aiming
mMovement.mRotation[0] = getXAngleToDir(vDirToTarget); mMovement.mRotation[0] = getXAngleToDir(vDirToTarget, distToTarget);
vDirToTarget.z = 0;
float distToTarget = vDirToTarget.length();
// (within strike dist) || (not quite strike dist while following) // (within strike dist) || (not quite strike dist while following)
if(distToTarget < rangeAttack || (distToTarget <= rangeFollow && mFollowTarget && !isStuck) ) if(distToTarget < rangeAttack || (distToTarget <= rangeFollow && mFollowTarget && !isStuck) )
{ {
//Melee and Close-up combat //Melee and Close-up combat
mMovement.mRotation[2] = getZAngleToDir(vDirToTarget, distToTarget);
// if we preserve dir.z then horizontal angle can be inaccurate
mMovement.mRotation[2] = getZAngleToDir(Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0));
// (not quite strike dist while following) // (not quite strike dist while following)
if (mFollowTarget && distToTarget > rangeAttack) if (mFollowTarget && distToTarget > rangeAttack)
@ -397,19 +408,15 @@ namespace MWMechanics
{ {
bool preferShortcut = false; bool preferShortcut = false;
bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target); bool inLOS = MWBase::Environment::get().getWorld()->getLOS(actor, target);
if(mReadyToAttack) isStuck = false;
// check if shortcut is available // check if shortcut is available
if(!isStuck if(inLOS && (!isStuck || mReadyToAttack)
&& (!mForceNoShortcut && (!mForceNoShortcut || (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST))
|| (Ogre::Vector3(mShortcutFailPos.pos) - vActorPos).length() >= PATHFIND_SHORTCUT_RETRY_DIST)
&& inLOS)
{ {
if(speed == 0.0f) speed = actorCls.getSpeed(actor); if(speed == 0.0f) speed = actorCls.getSpeed(actor);
// maximum dist before pit/obstacle for actor to avoid them depending on his speed // maximum dist before pit/obstacle for actor to avoid them depending on his speed
float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; // *2 - for reliability float maxAvoidDist = tReaction * speed + speed / MAX_VEL_ANGULAR.valueRadians() * 2; // *2 - for reliability
preferShortcut = checkWayIsClear(vActorPos, vTargetPos, distToTarget > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2); preferShortcut = checkWayIsClear(vActorPos, vTargetPos, Ogre::Vector3(vDirToTarget.x, vDirToTarget.y, 0).length() > maxAvoidDist*1.5? maxAvoidDist : maxAvoidDist/2);
} }
// don't use pathgrid when actor can move in 3 dimensions // don't use pathgrid when actor can move in 3 dimensions
@ -467,7 +474,7 @@ namespace MWMechanics
mReadyToAttack = false; mReadyToAttack = false;
} }
if(distToTarget > rangeAttack && !distantCombat) if(!isStuck && distToTarget > rangeAttack && !distantCombat)
{ {
//special run attack; it shouldn't affect melee combat tactics //special run attack; it shouldn't affect melee combat tactics
if(actorCls.getMovementSettings(actor).mPosition[1] == 1) if(actorCls.getMovementSettings(actor).mPosition[1] == 1)

View file

@ -137,7 +137,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor,float duration)
float nearestDist = std::numeric_limits<float>::max(); float nearestDist = std::numeric_limits<float>::max();
Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos);
for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end(); ++it) for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();)
{ {
if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break;
@ -147,7 +147,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor,float duration)
if (target.isEmpty()) if (target.isEmpty())
{ {
delete *it; delete *it;
mPackages.erase(it++); it = mPackages.erase(it);
} }
else else
{ {
@ -159,20 +159,26 @@ void AiSequence::execute (const MWWorld::Ptr& actor,float duration)
nearestDist = distTo; nearestDist = distTo;
itActualCombat = it; itActualCombat = it;
} }
++it;
} }
} }
// all targets disappeared if (!mPackages.empty())
if (nearestDist == std::numeric_limits<float>::max()) {
if (nearestDist < std::numeric_limits<float>::max() && mPackages.begin() != itActualCombat)
{
// move combat package with nearest target to the front
mPackages.splice(mPackages.begin(), mPackages, itActualCombat);
}
package = mPackages.front();
mLastAiPackage = package->getTypeId();
}
else
{ {
mDone = true; mDone = true;
return; return;
} }
else if (mPackages.begin() != itActualCombat)
{
// move combat package with nearest target to the front
mPackages.splice(mPackages.begin(), mPackages, itActualCombat);
}
} }
if (package->execute (actor,duration)) if (package->execute (actor,duration))

View file

@ -1022,7 +1022,9 @@ namespace MWMechanics
void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target) void MechanicsManager::startCombat(const MWWorld::Ptr &ptr, const MWWorld::Ptr &target)
{ {
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack"); if (ptr.getClass().isNpc())
MWBase::Environment::get().getDialogueManager()->say(ptr, "attack");
ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr); ptr.getClass().getCreatureStats(ptr).getAiSequence().stack(MWMechanics::AiCombat(target), ptr);
if (target == MWBase::Environment::get().getWorld()->getPlayerPtr()) if (target == MWBase::Environment::get().getWorld()->getPlayerPtr())
ptr.getClass().getCreatureStats(ptr).setHostile(true); ptr.getClass().getCreatureStats(ptr).setHostile(true);