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:
parent
bcb1f4ed05
commit
b304e98568
3 changed files with 64 additions and 79 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue