From b304e98568c15f7e180eef68414cabfa076d9753 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Fri, 15 Jan 2016 21:49:27 +0300 Subject: [PATCH] implement ActionWeapon::getCombatRange (move logic from AiCombat) --- apps/openmw/mwmechanics/aicombat.cpp | 68 ++++------------------ apps/openmw/mwmechanics/aicombataction.cpp | 62 +++++++++++++++----- apps/openmw/mwmechanics/aicombataction.hpp | 13 +++-- 3 files changed, 64 insertions(+), 79 deletions(-) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index abf4109ba..acdbef299 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -211,61 +211,13 @@ namespace MWMechanics actionCooldown = currentAction->getActionCooldown(); } - float rangeFollow; - if (currentAction.get()) - currentAction->getCombatRange(rangeAttack, rangeFollow); - - // FIXME: consider moving this stuff to ActionWeapon::getCombatRange const ESM::Weapon *weapon = NULL; - MWMechanics::WeaponType weaptype = WeapType_None; - float weapRange = 1.0f; - - // Get weapon characteristics - MWBase::World* world = MWBase::Environment::get().getWorld(); - if (actorClass.hasInventoryStore(actor)) - { - //Get weapon range - MWWorld::ContainerStoreIterator weaponSlot = - MWMechanics::getActiveWeapon(actorClass.getCreatureStats(actor), actorClass.getInventoryStore(actor), &weaptype); - - if (weaptype == WeapType_HandToHand) - { - static float fHandToHandReach = - world->getStore().get().find("fHandToHandReach")->getFloat(); - weapRange = fHandToHandReach; - } - else if (weaptype != WeapType_PickProbe && weaptype != WeapType_Spell && weaptype != WeapType_None) - { - // All other WeapTypes are actually weapons, so get is safe. - weapon = weaponSlot->get()->mBase; - weapRange = weapon->mData.mReach; - } - weapRange *= 100.0f; - } - else //is creature - { - weaptype = actorClass.getCreatureStats(actor).getDrawState() == DrawState_Spell ? WeapType_Spell : WeapType_HandToHand; - weapRange = 200; //TODO: use true attack range (the same problem in Creature::hit) - } - - bool distantCombat = false; - if (weaptype != WeapType_Spell) - { - // TODO: move to ActionWeapon - if (weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow || weaptype == WeapType_Thrown) - { - rangeAttack = 1000; - distantCombat = true; - } - else - { - rangeAttack = weapRange; - } - } - else + bool isRangedCombat = false; + if (currentAction.get()) { - distantCombat = (rangeAttack > 500); - weapRange = 200; + rangeAttack = currentAction->getCombatRange(isRangedCombat); + // Get weapon characteristics + weapon = currentAction->getWeapon(); } ESM::Position pos = actor.getRefData().getPosition(); @@ -286,15 +238,15 @@ namespace MWMechanics if (storage.mReadyToAttack) { - storage.startCombatMove(actorClass.isNpc(), distantCombat, distToTarget, rangeAttack); + storage.startCombatMove(actorClass.isNpc(), isRangedCombat, distToTarget, rangeAttack); // start new attack - storage.startAttackIfReady(actor, characterController, weapon, distantCombat); + storage.startAttackIfReady(actor, characterController, weapon, isRangedCombat); - if (distantCombat) + if (isRangedCombat) { // rotate actor taking into account target movement direction and projectile speed osg::Vec3f& lastTargetPos = storage.mLastTargetPos; - vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, AI_REACTION_TIME, weaptype, storage.mStrength); + vAimDir = AimDirToMovingTarget(actor, target, lastTargetPos, AI_REACTION_TIME, (weapon ? weapon->mData.mType : 0), storage.mStrength); lastTargetPos = vTargetPos; MWMechanics::Movement& movement = storage.mMovement; @@ -302,7 +254,7 @@ namespace MWMechanics movement.mRotation[2] = getZAngleToDir(vAimDir); } - storage.mAdjustAiming = distantCombat; + storage.mAdjustAiming = isRangedCombat; } } diff --git a/apps/openmw/mwmechanics/aicombataction.cpp b/apps/openmw/mwmechanics/aicombataction.cpp index 60446e524..76d5ed952 100644 --- a/apps/openmw/mwmechanics/aicombataction.cpp +++ b/apps/openmw/mwmechanics/aicombataction.cpp @@ -40,23 +40,20 @@ int getRangeTypes (const ESM::EffectList& effects) return types; } -void suggestCombatRange(int rangeTypes, float& rangeAttack, float& rangeFollow) +float suggestCombatRange(int rangeTypes) { if (rangeTypes & Touch) { - rangeAttack = 100.f; - rangeFollow = 300.f; + return 100.f; } else if (rangeTypes & Target) { - rangeAttack = 1000.f; - rangeFollow = 0.f; + return 1000.f; } else { // For Self spells, distance doesn't matter, so back away slightly to avoid enemy hits - rangeAttack = 600.f; - rangeFollow = 0.f; + return 600.f; } } @@ -394,11 +391,13 @@ namespace MWMechanics } } - void ActionSpell::getCombatRange(float& rangeAttack, float& rangeFollow) + float ActionSpell::getCombatRange (bool& isRanged) const { const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get().find(mSpellId); int types = getRangeTypes(spell->mEffects); - suggestCombatRange(types, rangeAttack, rangeFollow); + + isRanged = (types & RangeTypes::Target); + return suggestCombatRange(types); } void ActionEnchantedItem::prepare(const MWWorld::Ptr &actor) @@ -408,18 +407,17 @@ namespace MWMechanics actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Spell); } - void ActionEnchantedItem::getCombatRange(float& rangeAttack, float& rangeFollow) + float ActionEnchantedItem::getCombatRange(bool& isRanged) const { const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get().find(mItem->getClass().getEnchantment(*mItem)); int types = getRangeTypes(enchantment->mEffects); - suggestCombatRange(types, rangeAttack, rangeFollow); + return suggestCombatRange(types); } - void ActionPotion::getCombatRange(float& rangeAttack, float& rangeFollow) + float ActionPotion::getCombatRange(bool& isRanged) const { // distance doesn't matter, so back away slightly to avoid enemy hits - rangeAttack = 600.f; - rangeFollow = 0.f; + return 600.f; } void ActionPotion::prepare(const MWWorld::Ptr &actor) @@ -430,6 +428,8 @@ namespace MWMechanics void ActionWeapon::prepare(const MWWorld::Ptr &actor) { + mIsNpc = actor.getClass().isNpc(); + if (actor.getClass().hasInventoryStore(actor)) { if (mWeapon.isEmpty()) @@ -449,9 +449,39 @@ namespace MWMechanics actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Weapon); } - void ActionWeapon::getCombatRange(float& rangeAttack, float& rangeFollow) + float ActionWeapon::getCombatRange(bool& isRanged) const + { + isRanged = false; + + if (mWeapon.isEmpty()) + { + if (!mIsNpc) + return 200.f; // TODO: use true attack range (the same problem in Creature::hit) + else + { + static float fHandToHandReach = + MWBase::Environment::get().getWorld()->getStore().get().find("fHandToHandReach")->getFloat(); + + return fHandToHandReach * 100.0f; + } + } + + const ESM::Weapon* weapon = mWeapon.get()->mBase; + + if (weapon->mData.mType >= ESM::Weapon::MarksmanBow) + { + isRanged = true; + return 1000.f; + } + else + return weapon->mData.mReach * 100.0f; + } + + const ESM::Weapon* ActionWeapon::getWeapon() const { - // Already done in AiCombat itself + if (mWeapon.isEmpty()) + return NULL; + return mWeapon.get()->mBase; } boost::shared_ptr prepareNextAction(const MWWorld::Ptr &actor, const MWWorld::Ptr &target) diff --git a/apps/openmw/mwmechanics/aicombataction.hpp b/apps/openmw/mwmechanics/aicombataction.hpp index a4a398d05..22f543418 100644 --- a/apps/openmw/mwmechanics/aicombataction.hpp +++ b/apps/openmw/mwmechanics/aicombataction.hpp @@ -16,8 +16,9 @@ namespace MWMechanics public: virtual ~Action() {} virtual void prepare(const MWWorld::Ptr& actor) = 0; - virtual void getCombatRange (float& rangeAttack, float& rangeFollow) = 0; + virtual float getCombatRange (bool& isRanged) const = 0; virtual float getActionCooldown() { return 0.f; } + virtual const ESM::Weapon* getWeapon() const { return NULL; }; }; class ActionSpell : public Action @@ -28,7 +29,7 @@ namespace MWMechanics /// Sets the given spell as selected on the actor's spell list. virtual void prepare(const MWWorld::Ptr& actor); - virtual void getCombatRange (float& rangeAttack, float& rangeFollow); + virtual float getCombatRange (bool& isRanged) const; }; class ActionEnchantedItem : public Action @@ -38,7 +39,7 @@ namespace MWMechanics MWWorld::ContainerStoreIterator mItem; /// Sets the given item as selected enchanted item in the actor's InventoryStore. virtual void prepare(const MWWorld::Ptr& actor); - virtual void getCombatRange (float& rangeAttack, float& rangeFollow); + virtual float getCombatRange (bool& isRanged) const; /// Since this action has no animation, apply a small cool down for using it virtual float getActionCooldown() { return 1.f; } @@ -51,7 +52,7 @@ namespace MWMechanics MWWorld::Ptr mPotion; /// Drinks the given potion. virtual void prepare(const MWWorld::Ptr& actor); - virtual void getCombatRange (float& rangeAttack, float& rangeFollow); + virtual float getCombatRange (bool& isRanged) const; /// Since this action has no animation, apply a small cool down for using it virtual float getActionCooldown() { return 1.f; } @@ -62,6 +63,7 @@ namespace MWMechanics private: MWWorld::Ptr mAmmunition; MWWorld::Ptr mWeapon; + bool mIsNpc; public: /// \a weapon may be empty for hand-to-hand combat @@ -69,7 +71,8 @@ namespace MWMechanics : mAmmunition(ammo), mWeapon(weapon) {} /// Equips the given weapon. virtual void prepare(const MWWorld::Ptr& actor); - virtual void getCombatRange (float& rangeAttack, float& rangeFollow); + virtual float getCombatRange (bool& isRanged) const; + virtual const ESM::Weapon* getWeapon() const; }; float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);