1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-21 13:53:51 +00:00

implement ActionWeapon::getCombatRange (move logic from AiCombat)

This commit is contained in:
mrcheko 2016-01-15 21:49:27 +03:00
parent bcb1f4ed05
commit b304e98568
3 changed files with 64 additions and 79 deletions

View file

@ -211,61 +211,13 @@ namespace MWMechanics
actionCooldown = currentAction->getActionCooldown(); 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; const ESM::Weapon *weapon = NULL;
MWMechanics::WeaponType weaptype = WeapType_None; bool isRangedCombat = false;
float weapRange = 1.0f; if (currentAction.get())
{
rangeAttack = currentAction->getCombatRange(isRangedCombat);
// Get weapon characteristics // Get weapon characteristics
MWBase::World* world = MWBase::Environment::get().getWorld(); weapon = currentAction->getWeapon();
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<ESM::GameSetting>().find("fHandToHandReach")->getFloat();
weapRange = fHandToHandReach;
}
else if (weaptype != WeapType_PickProbe && weaptype != WeapType_Spell && weaptype != WeapType_None)
{
// All other WeapTypes are actually weapons, so get<ESM::Weapon> is safe.
weapon = weaponSlot->get<ESM::Weapon>()->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
{
distantCombat = (rangeAttack > 500);
weapRange = 200;
} }
ESM::Position pos = actor.getRefData().getPosition(); ESM::Position pos = actor.getRefData().getPosition();
@ -286,15 +238,15 @@ namespace MWMechanics
if (storage.mReadyToAttack) if (storage.mReadyToAttack)
{ {
storage.startCombatMove(actorClass.isNpc(), distantCombat, distToTarget, rangeAttack); storage.startCombatMove(actorClass.isNpc(), isRangedCombat, distToTarget, rangeAttack);
// start new attack // 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 // rotate actor taking into account target movement direction and projectile speed
osg::Vec3f& lastTargetPos = storage.mLastTargetPos; 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; lastTargetPos = vTargetPos;
MWMechanics::Movement& movement = storage.mMovement; MWMechanics::Movement& movement = storage.mMovement;
@ -302,7 +254,7 @@ namespace MWMechanics
movement.mRotation[2] = getZAngleToDir(vAimDir); movement.mRotation[2] = getZAngleToDir(vAimDir);
} }
storage.mAdjustAiming = distantCombat; storage.mAdjustAiming = isRangedCombat;
} }
} }

View file

@ -40,23 +40,20 @@ int getRangeTypes (const ESM::EffectList& effects)
return types; return types;
} }
void suggestCombatRange(int rangeTypes, float& rangeAttack, float& rangeFollow) float suggestCombatRange(int rangeTypes)
{ {
if (rangeTypes & Touch) if (rangeTypes & Touch)
{ {
rangeAttack = 100.f; return 100.f;
rangeFollow = 300.f;
} }
else if (rangeTypes & Target) else if (rangeTypes & Target)
{ {
rangeAttack = 1000.f; return 1000.f;
rangeFollow = 0.f;
} }
else else
{ {
// For Self spells, distance doesn't matter, so back away slightly to avoid enemy hits // For Self spells, distance doesn't matter, so back away slightly to avoid enemy hits
rangeAttack = 600.f; return 600.f;
rangeFollow = 0.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<ESM::Spell>().find(mSpellId); const ESM::Spell* spell = MWBase::Environment::get().getWorld()->getStore().get<ESM::Spell>().find(mSpellId);
int types = getRangeTypes(spell->mEffects); int types = getRangeTypes(spell->mEffects);
suggestCombatRange(types, rangeAttack, rangeFollow);
isRanged = (types & RangeTypes::Target);
return suggestCombatRange(types);
} }
void ActionEnchantedItem::prepare(const MWWorld::Ptr &actor) void ActionEnchantedItem::prepare(const MWWorld::Ptr &actor)
@ -408,18 +407,17 @@ namespace MWMechanics
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Spell); 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<ESM::Enchantment>().find(mItem->getClass().getEnchantment(*mItem)); const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(mItem->getClass().getEnchantment(*mItem));
int types = getRangeTypes(enchantment->mEffects); 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 // distance doesn't matter, so back away slightly to avoid enemy hits
rangeAttack = 600.f; return 600.f;
rangeFollow = 0.f;
} }
void ActionPotion::prepare(const MWWorld::Ptr &actor) void ActionPotion::prepare(const MWWorld::Ptr &actor)
@ -430,6 +428,8 @@ namespace MWMechanics
void ActionWeapon::prepare(const MWWorld::Ptr &actor) void ActionWeapon::prepare(const MWWorld::Ptr &actor)
{ {
mIsNpc = actor.getClass().isNpc();
if (actor.getClass().hasInventoryStore(actor)) if (actor.getClass().hasInventoryStore(actor))
{ {
if (mWeapon.isEmpty()) if (mWeapon.isEmpty())
@ -449,9 +449,39 @@ namespace MWMechanics
actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Weapon); actor.getClass().getCreatureStats(actor).setDrawState(DrawState_Weapon);
} }
void ActionWeapon::getCombatRange(float& rangeAttack, float& rangeFollow) float ActionWeapon::getCombatRange(bool& isRanged) const
{ {
// Already done in AiCombat itself 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<ESM::GameSetting>().find("fHandToHandReach")->getFloat();
return fHandToHandReach * 100.0f;
}
}
const ESM::Weapon* weapon = mWeapon.get<ESM::Weapon>()->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
{
if (mWeapon.isEmpty())
return NULL;
return mWeapon.get<ESM::Weapon>()->mBase;
} }
boost::shared_ptr<Action> prepareNextAction(const MWWorld::Ptr &actor, const MWWorld::Ptr &target) boost::shared_ptr<Action> prepareNextAction(const MWWorld::Ptr &actor, const MWWorld::Ptr &target)

View file

@ -16,8 +16,9 @@ namespace MWMechanics
public: public:
virtual ~Action() {} virtual ~Action() {}
virtual void prepare(const MWWorld::Ptr& actor) = 0; 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 float getActionCooldown() { return 0.f; }
virtual const ESM::Weapon* getWeapon() const { return NULL; };
}; };
class ActionSpell : public Action class ActionSpell : public Action
@ -28,7 +29,7 @@ namespace MWMechanics
/// Sets the given spell as selected on the actor's spell list. /// Sets the given spell as selected on the actor's spell list.
virtual void prepare(const MWWorld::Ptr& actor); virtual void prepare(const MWWorld::Ptr& actor);
virtual void getCombatRange (float& rangeAttack, float& rangeFollow); virtual float getCombatRange (bool& isRanged) const;
}; };
class ActionEnchantedItem : public Action class ActionEnchantedItem : public Action
@ -38,7 +39,7 @@ namespace MWMechanics
MWWorld::ContainerStoreIterator mItem; MWWorld::ContainerStoreIterator mItem;
/// Sets the given item as selected enchanted item in the actor's InventoryStore. /// Sets the given item as selected enchanted item in the actor's InventoryStore.
virtual void prepare(const MWWorld::Ptr& actor); 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 /// Since this action has no animation, apply a small cool down for using it
virtual float getActionCooldown() { return 1.f; } virtual float getActionCooldown() { return 1.f; }
@ -51,7 +52,7 @@ namespace MWMechanics
MWWorld::Ptr mPotion; MWWorld::Ptr mPotion;
/// Drinks the given potion. /// Drinks the given potion.
virtual void prepare(const MWWorld::Ptr& actor); 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 /// Since this action has no animation, apply a small cool down for using it
virtual float getActionCooldown() { return 1.f; } virtual float getActionCooldown() { return 1.f; }
@ -62,6 +63,7 @@ namespace MWMechanics
private: private:
MWWorld::Ptr mAmmunition; MWWorld::Ptr mAmmunition;
MWWorld::Ptr mWeapon; MWWorld::Ptr mWeapon;
bool mIsNpc;
public: public:
/// \a weapon may be empty for hand-to-hand combat /// \a weapon may be empty for hand-to-hand combat
@ -69,7 +71,8 @@ namespace MWMechanics
: mAmmunition(ammo), mWeapon(weapon) {} : mAmmunition(ammo), mWeapon(weapon) {}
/// Equips the given weapon. /// Equips the given weapon.
virtual void prepare(const MWWorld::Ptr& actor); 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); float rateSpell (const ESM::Spell* spell, const MWWorld::Ptr& actor, const MWWorld::Ptr& target);