diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f0feba89f8..2ad667d3f0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -159,20 +159,6 @@ namespace MWInput if (action == A_Use) { MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackingOrSpell(currentValue); - if (currentValue == 1) - { - int type = MWMechanics::CreatureStats::AT_Chop; - bool forward = (mInputBinder->getChannel(A_MoveForward)->getValue() > 0 - || mInputBinder->getChannel(A_MoveBackward)->getValue() > 0); - bool side = (mInputBinder->getChannel(A_MoveLeft)->getValue() > 0 - || mInputBinder->getChannel(A_MoveRight)->getValue() > 0); - if (side && !forward) - type = MWMechanics::CreatureStats::AT_Slash; - if (forward && !side) - type = MWMechanics::CreatureStats::AT_Thrust; - - MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).setAttackType(type); - } } if (currentValue == 1) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index f12a10f9b3..8f24085874 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -28,7 +28,6 @@ namespace return -1.0; } - void determineAttackType(const MWWorld::Ptr& actor, MWMechanics::Movement &movement); //chooses an attack depending on probability to avoid uniformity void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement); } @@ -57,9 +56,6 @@ namespace MWMechanics return true; //Update every frame - if(mReadyToAttack) - determineAttackType(actor, mMovement); - if(mCombatMove) { mTimerCombatMove -= duration; @@ -155,7 +151,7 @@ namespace MWMechanics else //is creature { weaptype = WeapType_HandToHand; //doesn't matter, should only reflect if it is melee or distant weapon - weapRange = 100; //TODO: use true attack range (the same problem in Creature::hit) + weapRange = 150; //TODO: use true attack range (the same problem in Creature::hit) } //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); @@ -167,7 +163,9 @@ namespace MWMechanics float rangeMelee; float rangeCloseUp; bool distantCombat = false; - if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_ThowWeapon) // || WeapType_Spell_OnTarget + int attackType = actor.getClass().getCreatureStats(actor).getAttackType(); + if (weaptype==WeapType_BowAndArrow || weaptype==WeapType_Crossbow || weaptype==WeapType_ThowWeapon + || attackType==MWMechanics::CreatureStats::AT_Target ) { rangeMelee = 1000; // TODO: should depend on archer skill rangeCloseUp = 0; //doesn't needed when attacking from distance @@ -251,7 +249,11 @@ namespace MWMechanics //delete visited path node mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); - zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + //try shortcut + if(vDir.length() < mPathFinder.getDistToNext(pos.pos[0],pos.pos[1],pos.pos[2]) && MWBase::Environment::get().getWorld()->getLOS(actor, mTarget)) + zAngle = Ogre::Radian( Ogre::Math::ACos(vDir.y / vDir.length()) * sgn(Ogre::Math::ASin(vDir.x / vDir.length())) ).valueDegrees(); + else + zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); // TODO: use movement settings instead of rotating directly MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); @@ -375,24 +377,12 @@ namespace MWMechanics namespace { -void determineAttackType(const MWWorld::Ptr& actor, MWMechanics::Movement &movement) -{ - if (movement.mPosition[0] && !movement.mPosition[1]) //sideway - actor.getClass().getCreatureStats(actor).setAttackType(MWMechanics::CreatureStats::AT_Slash); - else if (movement.mPosition[1]) //forward - actor.getClass().getCreatureStats(actor).setAttackType(MWMechanics::CreatureStats::AT_Thrust); - else - actor.getClass().getCreatureStats(actor).setAttackType(MWMechanics::CreatureStats::AT_Chop); -} void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement) { - //the more damage attackType deals the more probability it has - if (weapon == NULL) { - //hand-to-hand and creatures' attacks handled here - //hand-to-hand deals equal damage + //hand-to-hand and creatures' attacks deal equal damage for each type float roll = static_cast(rand())/RAND_MAX; if(roll <= 0.333f) //side punch { @@ -401,10 +391,15 @@ void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement } else if(roll <= 0.666f) //forward punch movement.mPosition[1] = 1; + else + { + movement.mPosition[1] = movement.mPosition[0] = 0; + } return; } + //the more damage attackType deals the more probability it has int slash = (weapon->mData.mSlash[0] + weapon->mData.mSlash[1])/2; int chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1])/2; int thrust = (weapon->mData.mThrust[0] + weapon->mData.mThrust[1])/2; @@ -419,7 +414,8 @@ void chooseBestAttack(const ESM::Weapon* weapon, MWMechanics::Movement &movement } else if(roll <= (static_cast(slash) + static_cast(thrust))/total) movement.mPosition[1] = 1; - //else chop + else + movement.mPosition[1] = movement.mPosition[0] = 0; } } \ No newline at end of file diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 967f7413a8..05c4e1f2ae 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -490,18 +490,7 @@ bool CharacterController::updateCreatureState() { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); - switch (stats.getAttackType()) - { - case CreatureStats::AT_Chop: - mCurrentWeapon = "attack1"; - break; - case CreatureStats::AT_Slash: - mCurrentWeapon = "attack2"; - break; - case CreatureStats::AT_Thrust: - mCurrentWeapon = "attack3"; - break; - } + determineAttackType(); mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_All, true, @@ -517,7 +506,7 @@ bool CharacterController::updateCreatureState() return false; } -bool CharacterController::updateNpcState(bool inwater, bool isrunning) +bool CharacterController::updateNpcState() { const MWWorld::Class &cls = MWWorld::Class::get(mPtr); NpcStats &stats = cls.getNpcStats(mPtr); @@ -586,7 +575,9 @@ bool CharacterController::updateNpcState(bool inwater, bool isrunning) if(isWerewolf) { MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); - if(isrunning && !inwater && mWeaponType == WeapType_None) + if(cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run) + && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) + && mWeaponType == WeapType_None) { if(!sndMgr->getSoundPlaying(mPtr, "WolfRun")) sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, @@ -653,12 +644,7 @@ bool CharacterController::updateNpcState(bool inwater, bool isrunning) mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Left Hand", effect->mParticle); mAnimation->addEffect("meshes\\" + castStatic->mModel, -1, false, "Right Hand", effect->mParticle); - switch(effectentry.mRange) - { - case 0: mAttackType = "self"; break; - case 1: mAttackType = "touch"; break; - case 2: mAttackType = "target"; break; - } + determineAttackType(effectentry.mRange); mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, true, @@ -715,13 +701,8 @@ bool CharacterController::updateNpcState(bool inwater, bool isrunning) int attackType = stats.getAttackType(); if(isWeapon && Settings::Manager::getBool("best attack", "Game")) attackType = getBestAttack(weapon->get()->mBase); - - if (attackType == MWMechanics::CreatureStats::AT_Chop) - mAttackType = "chop"; - else if (attackType == MWMechanics::CreatureStats::AT_Slash) - mAttackType = "slash"; else - mAttackType = "thrust"; + determineAttackType(); } mAnimation->play(mCurrentWeapon, Priority_Weapon, @@ -902,7 +883,8 @@ void CharacterController::update(float duration) bool isrunning = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run); bool sneak = cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Sneak); bool flying = world->isFlying(mPtr); - Ogre::Vector3 vec = cls.getMovementVector(mPtr); + //Ogre::Vector3 vec = cls.getMovementVector(mPtr); + Ogre::Vector3 vec(cls.getMovementSettings(mPtr).mPosition); vec.normalise(); if(mHitState != CharState_None && mJumpState == JumpState_None) vec = Ogre::Vector3(0.0f); @@ -1129,7 +1111,7 @@ void CharacterController::update(float duration) } if(cls.isNpc()) - forcestateupdate = updateNpcState(inwater, isrunning) || forcestateupdate; + forcestateupdate = updateNpcState() || forcestateupdate; else forcestateupdate = updateCreatureState() || forcestateupdate; @@ -1149,6 +1131,7 @@ void CharacterController::update(float duration) } movement = vec; + cls.getMovementSettings(mPtr).mPosition[0] = cls.getMovementSettings(mPtr).mPosition[1] = cls.getMovementSettings(mPtr).mPosition[2] = 0; } else if(cls.getCreatureStats(mPtr).isDead()) { @@ -1319,4 +1302,57 @@ void CharacterController::updateVisibility() mAnimation->setAlpha(alpha); } +void CharacterController::determineAttackType(int spellRange) +{ + if(spellRange == -1) + { + float * move = mPtr.getClass().getMovementSettings(mPtr).mPosition; + + if (move[0] && !move[1]) //sideway + { + mPtr.getClass().getCreatureStats(mPtr).setAttackType(MWMechanics::CreatureStats::AT_Slash); + if(mPtr.getClass().isNpc()) + mAttackType = "slash"; + else + mCurrentWeapon = "attack2"; + } + else if (move[1]) //forward + { + mPtr.getClass().getCreatureStats(mPtr).setAttackType(MWMechanics::CreatureStats::AT_Thrust); + if(mPtr.getClass().isNpc()) + mAttackType = "thrust"; + else + mCurrentWeapon = "attack3"; + } + else + { + mPtr.getClass().getCreatureStats(mPtr).setAttackType(MWMechanics::CreatureStats::AT_Chop); + if(mPtr.getClass().isNpc()) + mAttackType = "chop"; + else + mCurrentWeapon = "attack1"; + } + + } + else + { + switch(spellRange) + { + case 0: + mAttackType = "self"; + mPtr.getClass().getCreatureStats(mPtr).setAttackType(MWMechanics::CreatureStats::AT_Self); + break; + case 1: + mAttackType = "touch"; + mPtr.getClass().getCreatureStats(mPtr).setAttackType(MWMechanics::CreatureStats::AT_Touch); + break; + case 2: + mAttackType = "target"; + mPtr.getClass().getCreatureStats(mPtr).setAttackType(MWMechanics::CreatureStats::AT_Target); + break; + } + } + } + +} \ No newline at end of file diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 01985f38e8..37fc42f1e5 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -165,12 +165,13 @@ class CharacterController float mSecondsOfRunning; std::string mAttackType; // slash, chop or thrust + void determineAttackType(int spellRange = -1); void refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force=false); void clearAnimQueue(); - bool updateNpcState(bool inwater, bool isrunning); + bool updateNpcState(); bool updateCreatureState(); void updateVisibility(); diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 308883fc53..f9b52abc0d 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -118,7 +118,11 @@ namespace MWMechanics { AT_Chop, AT_Slash, - AT_Thrust + AT_Thrust, + + AT_Self, + AT_Touch, + AT_Target, }; void setAttackType(int attackType) { mAttackType = attackType; } int getAttackType() { return mAttackType; } diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index fd44fcc4ce..b9c8c5c4fd 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -201,6 +201,12 @@ namespace MWMechanics return Ogre::Radian(Ogre::Math::ACos(directionY / directionResult) * sgn(Ogre::Math::ASin(directionX / directionResult))).valueDegrees(); } + float PathFinder::getDistToNext(float x, float y, float z) + { + ESM::Pathgrid::Point nextPoint = *mPath.begin(); + return distance(nextPoint, x, y, z); + } + bool PathFinder::checkWaypoint(float x, float y, float z) { if(mPath.empty()) diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index de58f5db87..6f836dac7f 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -22,6 +22,8 @@ namespace MWMechanics ///< \Returns true if a way point was reached float getZAngleToNext(float x, float y) const; + float getDistToNext(float x, float y, float z); + bool isPathConstructed() const { return mIsPathConstructed;