mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 14:59:54 +00:00
Refactor weapon types behaviour
1. Move weapon types behaviour from switches to the table (should allow us to de-hardcode weapon types later) 2. Gereralize bones injection to actors skeletons (instead of using the hardcoded xbase_anim_sh.nif)
This commit is contained in:
parent
25dc06db73
commit
f0cef772fa
26 changed files with 777 additions and 589 deletions
|
@ -83,7 +83,7 @@ add_openmw_dir (mwmechanics
|
|||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
||||
aicast aiescort aiface aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||
character actors objects aistate coordinateconverter trading weaponpriority spellpriority
|
||||
character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype
|
||||
)
|
||||
|
||||
add_openmw_dir (mwstate
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "../mwrender/objects.hpp"
|
||||
#include "../mwrender/renderinginterface.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
|
@ -332,21 +333,13 @@ namespace MWClass
|
|||
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
||||
{
|
||||
MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
if(weapon == invStore.end())
|
||||
return std::make_pair(1,"");
|
||||
|
||||
if(weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
(weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow))
|
||||
if(weapon != invStore.end() && weapon->getTypeName() == typeid(ESM::Weapon).name())
|
||||
{
|
||||
return std::make_pair(3,"");
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||
if (MWMechanics::getWeaponType(ref->mBase->mData.mType)->mFlags & ESM::WeaponType::TwoHanded)
|
||||
return std::make_pair(3,"");
|
||||
}
|
||||
|
||||
return std::make_pair(1,"");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "../mwmechanics/combat.hpp"
|
||||
#include "../mwmechanics/autocalcspell.hpp"
|
||||
#include "../mwmechanics/difficultyscaling.hpp"
|
||||
#include "../mwmechanics/character.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
|
@ -1228,9 +1228,9 @@ namespace MWClass
|
|||
if (getNpcStats(ptr).isWerewolf()
|
||||
&& getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
|
||||
{
|
||||
MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None;
|
||||
MWMechanics::getActiveWeapon(getCreatureStats(ptr), getInventoryStore(ptr), &weaponType);
|
||||
if (weaponType == MWMechanics::WeapType_None)
|
||||
int weaponType = ESM::Weapon::None;
|
||||
MWMechanics::getActiveWeapon(ptr, &weaponType);
|
||||
if (weaponType == ESM::Weapon::None)
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "../mwphysics/physicssystem.hpp"
|
||||
#include "../mwworld/nullaction.hpp"
|
||||
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "../mwgui/tooltips.hpp"
|
||||
|
||||
#include "../mwrender/objects.hpp"
|
||||
|
@ -64,8 +66,9 @@ namespace MWClass
|
|||
bool Weapon::hasItemHealth (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
int type = ref->mBase->mData.mType;
|
||||
|
||||
return (ref->mBase->mData.mType < ESM::Weapon::MarksmanThrown); // thrown weapons and arrows/bolts don't have health, only quantity
|
||||
return MWMechanics::getWeaponType(type)->mFlags & ESM::WeaponType::HasHealth;
|
||||
}
|
||||
|
||||
int Weapon::getItemMaxHealth (const MWWorld::ConstPtr& ptr) const
|
||||
|
@ -86,16 +89,17 @@ namespace MWClass
|
|||
std::pair<std::vector<int>, bool> Weapon::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
ESM::WeaponType::Class weapClass = MWMechanics::getWeaponType(ref->mBase->mData.mType)->mWeaponClass;
|
||||
|
||||
std::vector<int> slots_;
|
||||
bool stack = false;
|
||||
|
||||
if (ref->mBase->mData.mType==ESM::Weapon::Arrow || ref->mBase->mData.mType==ESM::Weapon::Bolt)
|
||||
if (weapClass == ESM::WeaponType::Ammo)
|
||||
{
|
||||
slots_.push_back (int (MWWorld::InventoryStore::Slot_Ammunition));
|
||||
stack = true;
|
||||
}
|
||||
else if (ref->mBase->mData.mType==ESM::Weapon::MarksmanThrown)
|
||||
else if (weapClass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
slots_.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||
stack = true;
|
||||
|
@ -109,30 +113,9 @@ namespace MWClass
|
|||
int Weapon::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
int type = ref->mBase->mData.mType;
|
||||
|
||||
const int size = 12;
|
||||
|
||||
static const int sMapping[size][2] =
|
||||
{
|
||||
{ ESM::Weapon::ShortBladeOneHand, ESM::Skill::ShortBlade },
|
||||
{ ESM::Weapon::LongBladeOneHand, ESM::Skill::LongBlade },
|
||||
{ ESM::Weapon::LongBladeTwoHand, ESM::Skill::LongBlade },
|
||||
{ ESM::Weapon::BluntOneHand, ESM::Skill::BluntWeapon },
|
||||
{ ESM::Weapon::BluntTwoClose, ESM::Skill::BluntWeapon },
|
||||
{ ESM::Weapon::BluntTwoWide, ESM::Skill::BluntWeapon },
|
||||
{ ESM::Weapon::SpearTwoWide, ESM::Skill::Spear },
|
||||
{ ESM::Weapon::AxeOneHand, ESM::Skill::Axe },
|
||||
{ ESM::Weapon::AxeTwoHand, ESM::Skill::Axe },
|
||||
{ ESM::Weapon::MarksmanBow, ESM::Skill::Marksman },
|
||||
{ ESM::Weapon::MarksmanCrossbow, ESM::Skill::Marksman },
|
||||
{ ESM::Weapon::MarksmanThrown, ESM::Skill::Marksman }
|
||||
};
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
if (sMapping[i][0]==ref->mBase->mData.mType)
|
||||
return sMapping[i][1];
|
||||
|
||||
return -1;
|
||||
return MWMechanics::getWeaponType(type)->mSkill;
|
||||
}
|
||||
|
||||
int Weapon::getValue (const MWWorld::ConstPtr& ptr) const
|
||||
|
@ -152,89 +135,17 @@ namespace MWClass
|
|||
std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
|
||||
int type = ref->mBase->mData.mType;
|
||||
// Ammo
|
||||
if (type == 12 || type == 13)
|
||||
{
|
||||
return std::string("Item Ammo Up");
|
||||
}
|
||||
// Bow
|
||||
if (type == 9)
|
||||
{
|
||||
return std::string("Item Weapon Bow Up");
|
||||
}
|
||||
// Crossbow
|
||||
if (type == 10)
|
||||
{
|
||||
return std::string("Item Weapon Crossbow Up");
|
||||
}
|
||||
// Longblades, One hand and Two
|
||||
if (type == 1 || type == 2)
|
||||
{
|
||||
return std::string("Item Weapon Longblade Up");
|
||||
}
|
||||
// Shortblade
|
||||
if (type == 0)
|
||||
{
|
||||
return std::string("Item Weapon Shortblade Up");
|
||||
}
|
||||
// Spear
|
||||
if (type == 6)
|
||||
{
|
||||
return std::string("Item Weapon Spear Up");
|
||||
}
|
||||
// Blunts, Axes and Thrown weapons
|
||||
if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8 || type == 11)
|
||||
{
|
||||
return std::string("Item Weapon Blunt Up");
|
||||
}
|
||||
|
||||
return std::string("Item Misc Up");
|
||||
std::string soundId = MWMechanics::getWeaponType(type)->mSoundId;
|
||||
return soundId + " Up";
|
||||
}
|
||||
|
||||
std::string Weapon::getDownSoundId (const MWWorld::ConstPtr& ptr) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
|
||||
int type = ref->mBase->mData.mType;
|
||||
// Ammo
|
||||
if (type == 12 || type == 13)
|
||||
{
|
||||
return std::string("Item Ammo Down");
|
||||
}
|
||||
// Bow
|
||||
if (type == 9)
|
||||
{
|
||||
return std::string("Item Weapon Bow Down");
|
||||
}
|
||||
// Crossbow
|
||||
if (type == 10)
|
||||
{
|
||||
return std::string("Item Weapon Crossbow Down");
|
||||
}
|
||||
// Longblades, One hand and Two
|
||||
if (type == 1 || type == 2)
|
||||
{
|
||||
return std::string("Item Weapon Longblade Down");
|
||||
}
|
||||
// Shortblade
|
||||
if (type == 0)
|
||||
{
|
||||
return std::string("Item Weapon Shortblade Down");
|
||||
}
|
||||
// Spear
|
||||
if (type == 6)
|
||||
{
|
||||
return std::string("Item Weapon Spear Down");
|
||||
}
|
||||
// Blunts, Axes and Thrown weapons
|
||||
if (type == 3 || type == 4 || type == 5 || type == 7 || type == 8 || type == 11)
|
||||
{
|
||||
return std::string("Item Weapon Blunt Down");
|
||||
}
|
||||
|
||||
return std::string("Item Misc Down");
|
||||
std::string soundId = MWMechanics::getWeaponType(type)->mSoundId;
|
||||
return soundId + " Down";
|
||||
}
|
||||
|
||||
std::string Weapon::getInventoryIcon (const MWWorld::ConstPtr& ptr) const
|
||||
|
@ -254,6 +165,7 @@ namespace MWClass
|
|||
MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
|
||||
|
||||
MWGui::ToolTipInfo info;
|
||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||
|
@ -264,37 +176,26 @@ namespace MWClass
|
|||
std::string text;
|
||||
|
||||
// weapon type & damage
|
||||
if ((ref->mBase->mData.mType < ESM::Weapon::Arrow || Settings::Manager::getBool("show projectile damage", "Game")) && ref->mBase->mData.mType <= ESM::Weapon::Bolt)
|
||||
if (weaponType->mWeaponClass != ESM::WeaponType::Ammo || Settings::Manager::getBool("show projectile damage", "Game"))
|
||||
{
|
||||
text += "\n#{sType} ";
|
||||
|
||||
static std::map <int, std::pair <std::string, std::string> > mapping;
|
||||
if (mapping.empty())
|
||||
int skill = MWMechanics::getWeaponType(ref->mBase->mData.mType)->mSkill;
|
||||
const std::string type = ESM::Skill::sSkillNameIds[skill];
|
||||
std::string oneOrTwoHanded;
|
||||
if (weaponType->mWeaponClass == ESM::WeaponType::Melee)
|
||||
{
|
||||
mapping[ESM::Weapon::ShortBladeOneHand] = std::make_pair("sSkillShortblade", "sOneHanded");
|
||||
mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded");
|
||||
mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded");
|
||||
mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded");
|
||||
mapping[ESM::Weapon::BluntTwoClose] = std::make_pair("sSkillBluntweapon", "sTwoHanded");
|
||||
mapping[ESM::Weapon::BluntTwoWide] = std::make_pair("sSkillBluntweapon", "sTwoHanded");
|
||||
mapping[ESM::Weapon::SpearTwoWide] = std::make_pair("sSkillSpear", "sTwoHanded");
|
||||
mapping[ESM::Weapon::AxeOneHand] = std::make_pair("sSkillAxe", "sOneHanded");
|
||||
mapping[ESM::Weapon::AxeTwoHand] = std::make_pair("sSkillAxe", "sTwoHanded");
|
||||
mapping[ESM::Weapon::MarksmanBow] = std::make_pair("sSkillMarksman", "");
|
||||
mapping[ESM::Weapon::MarksmanCrossbow] = std::make_pair("sSkillMarksman", "");
|
||||
mapping[ESM::Weapon::MarksmanThrown] = std::make_pair("sSkillMarksman", "");
|
||||
mapping[ESM::Weapon::Arrow] = std::make_pair("sSkillMarksman", "");
|
||||
mapping[ESM::Weapon::Bolt] = std::make_pair("sSkillMarksman", "");
|
||||
if (weaponType->mFlags & ESM::WeaponType::TwoHanded)
|
||||
oneOrTwoHanded = "sTwoHanded";
|
||||
else
|
||||
oneOrTwoHanded = "sOneHanded";
|
||||
}
|
||||
|
||||
const std::string type = mapping[ref->mBase->mData.mType].first;
|
||||
const std::string oneOrTwoHanded = mapping[ref->mBase->mData.mType].second;
|
||||
|
||||
text += store.get<ESM::GameSetting>().find(type)->mValue.getString() +
|
||||
((oneOrTwoHanded != "") ? ", " + store.get<ESM::GameSetting>().find(oneOrTwoHanded)->mValue.getString() : "");
|
||||
|
||||
// weapon damage
|
||||
if (ref->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
if (weaponType->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
// Thrown weapons have 2x real damage applied
|
||||
// as they're both the weapon and the ammo
|
||||
|
@ -302,14 +203,7 @@ namespace MWClass
|
|||
+ MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[0] * 2))
|
||||
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[1] * 2));
|
||||
}
|
||||
else if (ref->mBase->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||
{
|
||||
// marksman
|
||||
text += "\n#{sAttack}: "
|
||||
+ MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[0]))
|
||||
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[1]));
|
||||
}
|
||||
else
|
||||
else if (weaponType->mWeaponClass == ESM::WeaponType::Melee)
|
||||
{
|
||||
// Chop
|
||||
text += "\n#{sChop}: "
|
||||
|
@ -324,6 +218,13 @@ namespace MWClass
|
|||
+ MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mThrust[0]))
|
||||
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mThrust[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// marksman
|
||||
text += "\n#{sAttack}: "
|
||||
+ MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[0]))
|
||||
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[1]));
|
||||
}
|
||||
}
|
||||
|
||||
if (hasItemHealth(ptr))
|
||||
|
@ -335,7 +236,7 @@ namespace MWClass
|
|||
|
||||
const bool verbose = Settings::Manager::getBool("show melee info", "Game");
|
||||
// add reach for melee weapon
|
||||
if (ref->mBase->mData.mType < ESM::Weapon::MarksmanBow && verbose)
|
||||
if (weaponType->mWeaponClass == ESM::WeaponType::Melee && verbose)
|
||||
{
|
||||
// display value in feet
|
||||
const float combatDistance = store.get<ESM::GameSetting>().find("fCombatDistance")->mValue.getFloat() * ref->mBase->mData.mReach;
|
||||
|
@ -344,7 +245,7 @@ namespace MWClass
|
|||
}
|
||||
|
||||
// add attack speed for any weapon excepts arrows and bolts
|
||||
if (ref->mBase->mData.mType < ESM::Weapon::Arrow && verbose)
|
||||
if (weaponType->mWeaponClass != ESM::WeaponType::Ammo && verbose)
|
||||
{
|
||||
text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mSpeed, "#{sAttributeSpeed}");
|
||||
}
|
||||
|
@ -403,13 +304,8 @@ namespace MWClass
|
|||
if (slots_.first.empty())
|
||||
return std::make_pair (0, "");
|
||||
|
||||
if(ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
|
||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
|
||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoWide ||
|
||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::SpearTwoWide ||
|
||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::AxeTwoHand ||
|
||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow ||
|
||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
int type = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
if(MWMechanics::getWeaponType(type)->mFlags & ESM::WeaponType::TwoHanded)
|
||||
{
|
||||
return std::make_pair (2, "");
|
||||
}
|
||||
|
|
|
@ -445,10 +445,9 @@ namespace MWMechanics
|
|||
|
||||
if (targetClass.hasInventoryStore(target))
|
||||
{
|
||||
MWMechanics::WeaponType weapType = WeapType_None;
|
||||
MWWorld::ContainerStoreIterator weaponSlot =
|
||||
MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType);
|
||||
if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand)
|
||||
int weapType = ESM::Weapon::None;
|
||||
MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(target, &weapType);
|
||||
if (weapType > ESM::Weapon::None)
|
||||
targetWeapon = *weaponSlot;
|
||||
}
|
||||
|
||||
|
@ -645,7 +644,7 @@ osg::Vec3f AimDirToMovingTarget(const MWWorld::Ptr& actor, const MWWorld::Ptr& t
|
|||
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||
|
||||
// get projectile speed (depending on weapon type)
|
||||
if (weapType == ESM::Weapon::MarksmanThrown)
|
||||
if (MWMechanics::getWeaponType(weapType)->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
static float fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat();
|
||||
static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "combat.hpp"
|
||||
#include "weaponpriority.hpp"
|
||||
#include "spellpriority.hpp"
|
||||
#include "weapontype.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -125,8 +126,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
const ESM::Weapon* weapon = mWeapon.get<ESM::Weapon>()->mBase;
|
||||
|
||||
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||
if (MWMechanics::getWeaponType(weapon->mData.mType)->mWeaponClass != ESM::WeaponType::Melee)
|
||||
{
|
||||
isRanged = true;
|
||||
return fProjectileMaxSpeed;
|
||||
|
@ -194,11 +194,12 @@ namespace MWMechanics
|
|||
if (rating > bestActionRating)
|
||||
{
|
||||
const ESM::Weapon* weapon = it->get<ESM::Weapon>()->mBase;
|
||||
int ammotype = getWeaponType(weapon->mData.mType)->mAmmoType;
|
||||
|
||||
MWWorld::Ptr ammo;
|
||||
if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
|
||||
if (ammotype == ESM::Weapon::Arrow)
|
||||
ammo = bestArrow;
|
||||
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
else if (ammotype == ESM::Weapon::Bolt)
|
||||
ammo = bestBolt;
|
||||
|
||||
bestActionRating = rating;
|
||||
|
@ -367,7 +368,7 @@ namespace MWMechanics
|
|||
else if (!activeWeapon.isEmpty())
|
||||
{
|
||||
const ESM::Weapon* esmWeap = activeWeapon.get<ESM::Weapon>()->mBase;
|
||||
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||
if (MWMechanics::getWeaponType(esmWeap->mData.mType)->mWeaponClass != ESM::WeaponType::Melee)
|
||||
{
|
||||
static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
|
||||
dist = fTargetSpellMaxSpeed;
|
||||
|
|
|
@ -198,33 +198,6 @@ public:
|
|||
};
|
||||
|
||||
|
||||
static const struct WeaponInfo {
|
||||
WeaponType type;
|
||||
const char shortgroup[16];
|
||||
const char longgroup[16];
|
||||
} sWeaponTypeList[] = {
|
||||
{ WeapType_HandToHand, "hh", "handtohand" },
|
||||
{ WeapType_OneHand, "1h", "weapononehand" },
|
||||
{ WeapType_TwoHand, "2c", "weapontwohand" },
|
||||
{ WeapType_TwoWide, "2w", "weapontwowide" },
|
||||
{ WeapType_BowAndArrow, "1h", "bowandarrow" },
|
||||
{ WeapType_Crossbow, "crossbow", "crossbow" },
|
||||
{ WeapType_Thrown, "1h", "throwweapon" },
|
||||
{ WeapType_PickProbe, "1h", "pickprobe" },
|
||||
{ WeapType_Spell, "spell", "spellcast" },
|
||||
};
|
||||
static const WeaponInfo *sWeaponTypeListEnd = &sWeaponTypeList[sizeof(sWeaponTypeList)/sizeof(sWeaponTypeList[0])];
|
||||
|
||||
class FindWeaponType {
|
||||
WeaponType type;
|
||||
|
||||
public:
|
||||
FindWeaponType(WeaponType _type) : type(_type) { }
|
||||
|
||||
bool operator()(const WeaponInfo &weap) const
|
||||
{ return weap.type == type; }
|
||||
};
|
||||
|
||||
std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) const
|
||||
{
|
||||
int numAnims=0;
|
||||
|
@ -315,7 +288,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
|||
{
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
if (mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell)
|
||||
if (mWeaponType > ESM::Weapon::None)
|
||||
mAnimation->showWeapons(true);
|
||||
}
|
||||
else if (mUpperBodyState > UpperCharState_Nothing && mUpperBodyState < UpperCharState_WeapEquiped)
|
||||
|
@ -347,7 +320,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
|||
idle = CharState_None;
|
||||
}
|
||||
|
||||
void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force)
|
||||
void CharacterController::refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force)
|
||||
{
|
||||
if (!force && jump == mJumpState && idle == CharState_None)
|
||||
return;
|
||||
|
@ -357,9 +330,9 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
|
|||
if (jump != JumpState_None)
|
||||
{
|
||||
jumpAnimName = "jump";
|
||||
if(weap != sWeaponTypeListEnd)
|
||||
if(!weapShortGroup.empty())
|
||||
{
|
||||
jumpAnimName += weap->shortgroup;
|
||||
jumpAnimName += weapShortGroup;
|
||||
if(!mAnimation->hasAnimation(jumpAnimName))
|
||||
{
|
||||
jumpmask = MWRender::Animation::BlendMask_LowerBody;
|
||||
|
@ -371,7 +344,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
|
|||
idle = CharState_Idle;
|
||||
|
||||
// For crossbow animations use 1h ones as fallback
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
jumpAnimName += "1h";
|
||||
}
|
||||
}
|
||||
|
@ -446,7 +419,7 @@ void CharacterController::onClose()
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterController::refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force)
|
||||
void CharacterController::refreshMovementAnims(const std::string& weapShortGroup, CharacterState movement, CharacterState& idle, bool force)
|
||||
{
|
||||
if (movement == mMovementState && idle == mIdleState && !force)
|
||||
return;
|
||||
|
@ -460,15 +433,15 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
|||
if(movestate != sMovementListEnd)
|
||||
{
|
||||
movementAnimName = movestate->groupname;
|
||||
if(weap != sWeaponTypeListEnd)
|
||||
if(!weapShortGroup.empty())
|
||||
{
|
||||
std::string::size_type swimpos = movementAnimName.find("swim");
|
||||
if (swimpos == std::string::npos)
|
||||
{
|
||||
if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
|
||||
movementAnimName = weap->shortgroup + movementAnimName;
|
||||
if (mWeaponType == ESM::Weapon::Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
|
||||
movementAnimName = weapShortGroup + movementAnimName;
|
||||
else
|
||||
movementAnimName += weap->shortgroup;
|
||||
movementAnimName += weapShortGroup;
|
||||
}
|
||||
|
||||
if(!mAnimation->hasAnimation(movementAnimName))
|
||||
|
@ -483,7 +456,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
|||
idle = CharState_Idle;
|
||||
|
||||
// For crossbow animations use 1h ones as fallback
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
movementAnimName += "1h";
|
||||
}
|
||||
else if (idle == CharState_None)
|
||||
|
@ -521,13 +494,13 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
|||
else
|
||||
{
|
||||
// For crossbow animations use 1h ones as fallback
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
movementAnimName += "1h";
|
||||
|
||||
movementAnimName.erase(swimpos, 4);
|
||||
if (weap != sWeaponTypeListEnd)
|
||||
if (!weapShortGroup.empty())
|
||||
{
|
||||
std::string weapMovementAnimName = movementAnimName + weap->shortgroup;
|
||||
std::string weapMovementAnimName = movementAnimName + weapShortGroup;
|
||||
if(mAnimation->hasAnimation(weapMovementAnimName))
|
||||
movementAnimName = weapMovementAnimName;
|
||||
else
|
||||
|
@ -598,7 +571,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force)
|
||||
void CharacterController::refreshIdleAnims(const std::string& weapShortGroup, CharacterState idle, bool force)
|
||||
{
|
||||
// FIXME: if one of the below states is close to their last animation frame (i.e. will be disabled in the coming update),
|
||||
// the idle animation should be displayed
|
||||
|
@ -630,9 +603,9 @@ void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterStat
|
|||
else if(mIdleState != CharState_None)
|
||||
{
|
||||
idleGroup = "idle";
|
||||
if(weap != sWeaponTypeListEnd)
|
||||
if(!weapShortGroup.empty())
|
||||
{
|
||||
idleGroup += weap->shortgroup;
|
||||
idleGroup += weapShortGroup;
|
||||
if(!mAnimation->hasAnimation(idleGroup))
|
||||
idleGroup = "idle";
|
||||
|
||||
|
@ -669,9 +642,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
if (mPtr.getClass().isActor())
|
||||
refreshHitRecoilAnims(idle);
|
||||
|
||||
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||
weap = sWeaponTypeListEnd;
|
||||
std::string weap;
|
||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||
weap = getWeaponType(mWeaponType)->mShortGroup;
|
||||
|
||||
refreshJumpAnims(weap, jump, idle, force);
|
||||
refreshMovementAnims(weap, movement, idle, force);
|
||||
|
@ -680,77 +653,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
|||
refreshIdleAnims(weap, idle, force);
|
||||
}
|
||||
|
||||
|
||||
void getWeaponGroup(WeaponType weaptype, std::string &group)
|
||||
{
|
||||
const WeaponInfo *info = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(weaptype));
|
||||
if(info != sWeaponTypeListEnd)
|
||||
group = info->longgroup;
|
||||
else
|
||||
group.clear();
|
||||
}
|
||||
|
||||
|
||||
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype)
|
||||
{
|
||||
if(stats.getDrawState() == DrawState_Spell)
|
||||
{
|
||||
*weaptype = WeapType_Spell;
|
||||
return inv.end();
|
||||
}
|
||||
|
||||
if(stats.getDrawState() == MWMechanics::DrawState_Weapon)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon == inv.end())
|
||||
*weaptype = WeapType_HandToHand;
|
||||
else
|
||||
{
|
||||
const std::string &type = weapon->getTypeName();
|
||||
if(type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name())
|
||||
*weaptype = WeapType_PickProbe;
|
||||
else if(type == typeid(ESM::Weapon).name())
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||
ESM::Weapon::Type weaponType = (ESM::Weapon::Type)ref->mBase->mData.mType;
|
||||
switch(weaponType)
|
||||
{
|
||||
case ESM::Weapon::ShortBladeOneHand:
|
||||
case ESM::Weapon::LongBladeOneHand:
|
||||
case ESM::Weapon::BluntOneHand:
|
||||
case ESM::Weapon::AxeOneHand:
|
||||
case ESM::Weapon::Arrow:
|
||||
case ESM::Weapon::Bolt:
|
||||
*weaptype = WeapType_OneHand;
|
||||
break;
|
||||
case ESM::Weapon::LongBladeTwoHand:
|
||||
case ESM::Weapon::BluntTwoClose:
|
||||
case ESM::Weapon::AxeTwoHand:
|
||||
*weaptype = WeapType_TwoHand;
|
||||
break;
|
||||
case ESM::Weapon::BluntTwoWide:
|
||||
case ESM::Weapon::SpearTwoWide:
|
||||
*weaptype = WeapType_TwoWide;
|
||||
break;
|
||||
case ESM::Weapon::MarksmanBow:
|
||||
*weaptype = WeapType_BowAndArrow;
|
||||
break;
|
||||
case ESM::Weapon::MarksmanCrossbow:
|
||||
*weaptype = WeapType_Crossbow;
|
||||
break;
|
||||
case ESM::Weapon::MarksmanThrown:
|
||||
*weaptype = WeapType_Thrown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return weapon;
|
||||
}
|
||||
|
||||
return inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
}
|
||||
|
||||
void CharacterController::playDeath(float startpoint, CharacterState death)
|
||||
{
|
||||
// Make sure the character was swimming upon death for forward-compatibility
|
||||
|
@ -881,7 +783,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
, mHitState(CharState_None)
|
||||
, mUpperBodyState(UpperCharState_Nothing)
|
||||
, mJumpState(JumpState_None)
|
||||
, mWeaponType(WeapType_None)
|
||||
, mWeaponType(ESM::Weapon::None)
|
||||
, mAttackStrength(0.f)
|
||||
, mSkipAnim(false)
|
||||
, mSecondsOfSwimming(0)
|
||||
|
@ -905,19 +807,20 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
|||
|
||||
if (cls.hasInventoryStore(mPtr))
|
||||
{
|
||||
getActiveWeapon(cls.getCreatureStats(mPtr), cls.getInventoryStore(mPtr), &mWeaponType);
|
||||
if (mWeaponType != WeapType_None)
|
||||
getActiveWeapon(mPtr, &mWeaponType);
|
||||
if (mWeaponType != ESM::Weapon::None)
|
||||
{
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||
mCurrentWeapon = getWeaponType(mWeaponType)->mLongGroup;
|
||||
}
|
||||
|
||||
if(mWeaponType != WeapType_None && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand)
|
||||
if(mWeaponType != ESM::Weapon::None && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::HandToHand)
|
||||
{
|
||||
mAnimation->showWeapons(true);
|
||||
// Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly,
|
||||
// for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example)
|
||||
bool useRelativeDuration = mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Crossbow;
|
||||
ESM::WeaponType::Class weaponClass = getWeaponType(mWeaponType)->mWeaponClass;
|
||||
bool useRelativeDuration = weaponClass == ESM::WeaponType::Ranged;
|
||||
mAnimation->setWeaponGroup(mCurrentWeapon, useRelativeDuration);
|
||||
}
|
||||
|
||||
|
@ -1157,11 +1060,11 @@ bool CharacterController::updateCreatureState()
|
|||
const MWWorld::Class &cls = mPtr.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
||||
|
||||
WeaponType weapType = WeapType_None;
|
||||
int weapType = ESM::Weapon::None;
|
||||
if(stats.getDrawState() == DrawState_Weapon)
|
||||
weapType = WeapType_HandToHand;
|
||||
weapType = ESM::Weapon::HandToHand;
|
||||
else if (stats.getDrawState() == DrawState_Spell)
|
||||
weapType = WeapType_Spell;
|
||||
weapType = ESM::Weapon::Spell;
|
||||
|
||||
if (weapType != mWeaponType)
|
||||
{
|
||||
|
@ -1178,7 +1081,7 @@ bool CharacterController::updateCreatureState()
|
|||
|
||||
std::string startKey = "start";
|
||||
std::string stopKey = "stop";
|
||||
if (weapType == WeapType_Spell)
|
||||
if (weapType == ESM::Weapon::Spell)
|
||||
{
|
||||
const std::string spellid = stats.getSpells().getSelectedSpell();
|
||||
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
|
||||
|
@ -1214,7 +1117,7 @@ bool CharacterController::updateCreatureState()
|
|||
mCurrentWeapon = "";
|
||||
}
|
||||
|
||||
if (weapType != WeapType_Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
|
||||
if (weapType != ESM::Weapon::Spell || !mAnimation->hasAnimation("spellcast")) // Not all creatures have a dedicated spellcast animation
|
||||
{
|
||||
mCurrentWeapon = chooseRandomAttackAnimation();
|
||||
}
|
||||
|
@ -1229,7 +1132,7 @@ bool CharacterController::updateCreatureState()
|
|||
|
||||
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
||||
|
||||
if (weapType == WeapType_HandToHand)
|
||||
if (weapType == ESM::Weapon::HandToHand)
|
||||
playSwishSound(0.0f);
|
||||
}
|
||||
}
|
||||
|
@ -1243,34 +1146,23 @@ bool CharacterController::updateCreatureState()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool CharacterController::updateCarriedLeftVisible(WeaponType weaptype) const
|
||||
bool CharacterController::updateCarriedLeftVisible(const int weaptype) const
|
||||
{
|
||||
// Shields/torches shouldn't be visible during any operation involving two hands
|
||||
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
|
||||
// but they are also present in weapon drawing animation.
|
||||
switch (weaptype)
|
||||
{
|
||||
case WeapType_Spell:
|
||||
case WeapType_BowAndArrow:
|
||||
case WeapType_Crossbow:
|
||||
case WeapType_HandToHand:
|
||||
case WeapType_TwoHand:
|
||||
case WeapType_TwoWide:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
return !(getWeaponType(weaptype)->mFlags & ESM::WeaponType::TwoHanded);
|
||||
}
|
||||
|
||||
bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||
{
|
||||
const MWWorld::Class &cls = mPtr.getClass();
|
||||
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
||||
WeaponType weaptype = WeapType_None;
|
||||
int weaptype = ESM::Weapon::None;
|
||||
if(stats.getDrawState() == DrawState_Weapon)
|
||||
weaptype = WeapType_HandToHand;
|
||||
weaptype = ESM::Weapon::HandToHand;
|
||||
else if (stats.getDrawState() == DrawState_Spell)
|
||||
weaptype = WeapType_Spell;
|
||||
weaptype = ESM::Weapon::Spell;
|
||||
|
||||
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
|
||||
|
||||
|
@ -1280,18 +1172,18 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||
{
|
||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
||||
MWWorld::ContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
|
||||
MWWorld::ContainerStoreIterator weapon = getActiveWeapon(mPtr, &weaptype);
|
||||
if(stats.getDrawState() == DrawState_Spell)
|
||||
weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
|
||||
if(weapon != inv.end() && mWeaponType != WeapType_HandToHand && weaptype > WeapType_HandToHand && weaptype < WeapType_Spell)
|
||||
if(weapon != inv.end() && mWeaponType != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::Spell && weaptype != ESM::Weapon::None)
|
||||
upSoundId = weapon->getClass().getUpSoundId(*weapon);
|
||||
|
||||
if(weapon != inv.end() && mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell)
|
||||
if(weapon != inv.end() && mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None)
|
||||
downSoundId = weapon->getClass().getDownSoundId(*weapon);
|
||||
|
||||
// weapon->HtH switch: weapon is empty already, so we need to take sound from previous weapon
|
||||
if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == WeapType_HandToHand && mWeaponType != WeapType_Spell)
|
||||
if(weapon == inv.end() && !mWeapon.isEmpty() && weaptype == ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell)
|
||||
downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
|
||||
|
||||
MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
||||
|
@ -1312,8 +1204,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
bool forcestateupdate = false;
|
||||
|
||||
// We should not play equipping animation and sound during weapon->weapon transition
|
||||
bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell &&
|
||||
mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell;
|
||||
bool isStillWeapon = weaptype != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::Spell && weaptype != ESM::Weapon::None &&
|
||||
mWeaponType != ESM::Weapon::HandToHand && mWeaponType != ESM::Weapon::Spell && mWeaponType != ESM::Weapon::None;
|
||||
|
||||
// If the current weapon type was changed in the middle of attack (e.g. by Equip console command or when bound spell expires),
|
||||
// we should force actor to the "weapon equipped" state, interrupt attack and update animations.
|
||||
|
@ -1331,7 +1223,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if(!isKnockedOut() && !isKnockedDown() && !isRecovery())
|
||||
{
|
||||
std::string weapgroup;
|
||||
if ((!isWerewolf || mWeaponType != WeapType_Spell)
|
||||
if ((!isWerewolf || mWeaponType != ESM::Weapon::Spell)
|
||||
&& weaptype != mWeaponType
|
||||
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
||||
&& !isStillWeapon)
|
||||
|
@ -1340,7 +1232,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if (!weaponChanged)
|
||||
{
|
||||
// Note: we do not disable unequipping animation automatically to avoid body desync
|
||||
getWeaponGroup(mWeaponType, weapgroup);
|
||||
weapgroup = getWeaponType(mWeaponType)->mLongGroup;
|
||||
mAnimation->play(weapgroup, priorityWeapon,
|
||||
MWRender::Animation::BlendMask_All, false,
|
||||
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
||||
|
@ -1369,16 +1261,17 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
forcestateupdate = true;
|
||||
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
|
||||
|
||||
getWeaponGroup(weaptype, weapgroup);
|
||||
weapgroup = getWeaponType(weaptype)->mLongGroup;
|
||||
// Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly,
|
||||
// for other weapons they should use absolute time. Some mods rely on this behaviour (to rotate throwing projectiles, for example)
|
||||
bool useRelativeDuration = weaptype == WeapType_BowAndArrow || weaptype == WeapType_Crossbow;
|
||||
ESM::WeaponType::Class weaponClass = getWeaponType(weaptype)->mWeaponClass;
|
||||
bool useRelativeDuration = weaponClass == ESM::WeaponType::Ranged;
|
||||
mAnimation->setWeaponGroup(weapgroup, useRelativeDuration);
|
||||
|
||||
if (!isStillWeapon)
|
||||
{
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
if (weaptype != WeapType_None)
|
||||
if (weaptype != ESM::Weapon::None)
|
||||
{
|
||||
mAnimation->showWeapons(false);
|
||||
mAnimation->play(weapgroup, priorityWeapon,
|
||||
|
@ -1387,7 +1280,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
mUpperBodyState = UpperCharState_EquipingWeap;
|
||||
|
||||
// If we do not have the "equip attach" key, show weapon manually.
|
||||
if (weaptype != WeapType_Spell)
|
||||
if (weaptype != ESM::Weapon::Spell)
|
||||
{
|
||||
if (mAnimation->getTextKeyTime(weapgroup+": equip attach") < 0)
|
||||
mAnimation->showWeapons(true);
|
||||
|
@ -1407,7 +1300,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
}
|
||||
|
||||
mWeaponType = weaptype;
|
||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||
mCurrentWeapon = getWeaponType(mWeaponType)->mLongGroup;
|
||||
|
||||
if(!upSoundId.empty() && !isStillWeapon)
|
||||
{
|
||||
|
@ -1421,8 +1314,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
{
|
||||
mUpperBodyState = UpperCharState_Nothing;
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
mWeaponType = WeapType_None;
|
||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
||||
mWeaponType = ESM::Weapon::None;
|
||||
mCurrentWeapon = getWeaponType(mWeaponType)->mLongGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1433,7 +1326,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if(cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run)
|
||||
&& mHasMovedInXY
|
||||
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr)
|
||||
&& mWeaponType == WeapType_None)
|
||||
&& mWeaponType == ESM::Weapon::None)
|
||||
{
|
||||
if(!sndMgr->getSoundPlaying(mPtr, "WolfRun"))
|
||||
sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWSound::Type::Sfx,
|
||||
|
@ -1450,16 +1343,17 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||
{
|
||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr);
|
||||
MWWorld::ConstContainerStoreIterator weapon = getActiveWeapon(stats, inv, &weaptype);
|
||||
MWWorld::ConstContainerStoreIterator weapon = getActiveWeapon(mPtr, &weaptype);
|
||||
isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name());
|
||||
if(isWeapon)
|
||||
if (isWeapon)
|
||||
{
|
||||
weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
int ammotype = getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mAmmoType;
|
||||
if (ammotype != ESM::Weapon::None && (ammo == inv.end() || ammo->get<ESM::Weapon>()->mBase->mData.mType != ammotype))
|
||||
ammunition = false;
|
||||
}
|
||||
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt);
|
||||
else if (mWeaponType == WeapType_BowAndArrow)
|
||||
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow);
|
||||
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
|
||||
{
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
|
@ -1473,6 +1367,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
|
||||
float complete;
|
||||
bool animPlaying;
|
||||
ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass;
|
||||
if(mAttackingOrSpell)
|
||||
{
|
||||
MWWorld::Ptr player = getPlayer();
|
||||
|
@ -1491,7 +1386,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
mCurrentWeapon = chooseRandomAttackAnimation();
|
||||
}
|
||||
|
||||
if(mWeaponType == WeapType_Spell)
|
||||
if(mWeaponType == ESM::Weapon::Spell)
|
||||
{
|
||||
// Unset casting flag, otherwise pressing the mouse button down would
|
||||
// continue casting every frame if there is no animation
|
||||
|
@ -1597,7 +1492,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
resetIdle = false;
|
||||
}
|
||||
}
|
||||
else if(mWeaponType == WeapType_PickProbe)
|
||||
else if(mWeaponType == ESM::Weapon::PickProbe)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
MWWorld::Ptr item = *weapon;
|
||||
|
@ -1627,7 +1522,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
{
|
||||
std::string startKey;
|
||||
std::string stopKey;
|
||||
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Thrown)
|
||||
|
||||
if(weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
mAttackType = "shoot";
|
||||
startKey = mAttackType+" start";
|
||||
|
@ -1699,7 +1595,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
||||
}
|
||||
|
||||
if(mWeaponType != WeapType_Crossbow && mWeaponType != WeapType_BowAndArrow)
|
||||
if(weapclass != ESM::WeaponType::Ranged && weapclass != ESM::WeaponType::Thrown)
|
||||
{
|
||||
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||
|
||||
|
@ -1731,7 +1627,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if (mUpperBodyState > UpperCharState_WeapEquiped)
|
||||
{
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
if (mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell)
|
||||
if (mWeaponType > ESM::Weapon::None)
|
||||
mAnimation->showWeapons(true);
|
||||
}
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
|
@ -1739,9 +1635,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
}
|
||||
|
||||
mAnimation->setPitchFactor(0.f);
|
||||
if (mWeaponType == WeapType_BowAndArrow ||
|
||||
mWeaponType == WeapType_Thrown ||
|
||||
mWeaponType == WeapType_Crossbow)
|
||||
if (weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
switch (mUpperBodyState)
|
||||
{
|
||||
|
@ -1758,7 +1652,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
{
|
||||
// technically we do not need a pitch for crossbow reload animation,
|
||||
// but we should avoid abrupt repositioning
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
mAnimation->setPitchFactor(std::max(0.f, 1.f-complete*10.f));
|
||||
else
|
||||
mAnimation->setPitchFactor(1.f-complete);
|
||||
|
@ -1775,7 +1669,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
||||
mUpperBodyState == UpperCharState_CastingSpell)
|
||||
{
|
||||
if (ammunition && mWeaponType == WeapType_Crossbow)
|
||||
if (ammunition && mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
mAnimation->attachArrow();
|
||||
|
||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||
|
@ -1852,7 +1746,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
|||
if(!start.empty())
|
||||
{
|
||||
int mask = MWRender::Animation::BlendMask_All;
|
||||
if (mWeaponType == WeapType_Crossbow)
|
||||
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
mask = MWRender::Animation::BlendMask_UpperBody;
|
||||
|
||||
mAnimation->disable(mCurrentWeapon);
|
||||
|
@ -2639,7 +2533,7 @@ void CharacterController::resurrect()
|
|||
mAnimation->disable(mCurrentDeath);
|
||||
mCurrentDeath.clear();
|
||||
mDeathState = CharState_None;
|
||||
mWeaponType = WeapType_None;
|
||||
mWeaponType = ESM::Weapon::None;
|
||||
}
|
||||
|
||||
void CharacterController::updateContinuousVfx()
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include "../mwrender/animation.hpp"
|
||||
|
||||
#include "weapontype.hpp"
|
||||
|
||||
namespace MWWorld
|
||||
{
|
||||
class InventoryStore;
|
||||
|
@ -113,21 +115,6 @@ enum CharacterState {
|
|||
CharState_Block
|
||||
};
|
||||
|
||||
enum WeaponType {
|
||||
WeapType_None,
|
||||
|
||||
WeapType_HandToHand,
|
||||
WeapType_OneHand,
|
||||
WeapType_TwoHand,
|
||||
WeapType_TwoWide,
|
||||
WeapType_BowAndArrow,
|
||||
WeapType_Crossbow,
|
||||
WeapType_Thrown,
|
||||
WeapType_PickProbe,
|
||||
|
||||
WeapType_Spell
|
||||
};
|
||||
|
||||
enum UpperBodyCharacterState {
|
||||
UpperCharState_Nothing,
|
||||
UpperCharState_EquipingWeap,
|
||||
|
@ -186,7 +173,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
|||
JumpingState mJumpState;
|
||||
std::string mCurrentJump;
|
||||
|
||||
WeaponType mWeaponType;
|
||||
int mWeaponType;
|
||||
std::string mCurrentWeapon;
|
||||
|
||||
float mAttackStrength;
|
||||
|
@ -212,9 +199,9 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
|||
|
||||
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
|
||||
void refreshHitRecoilAnims(CharacterState& idle);
|
||||
void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false);
|
||||
void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false);
|
||||
void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false);
|
||||
void refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force=false);
|
||||
void refreshMovementAnims(const std::string& weapShortGroup, CharacterState movement, CharacterState& idle, bool force=false);
|
||||
void refreshIdleAnims(const std::string& weapShortGroup, CharacterState idle, bool force=false);
|
||||
|
||||
void clearAnimQueue(bool clearPersistAnims = false);
|
||||
|
||||
|
@ -241,7 +228,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
|||
/// @param num if non-nullptr, the chosen animation number will be written here
|
||||
std::string chooseRandomGroup (const std::string& prefix, int* num = nullptr) const;
|
||||
|
||||
bool updateCarriedLeftVisible(WeaponType weaptype) const;
|
||||
bool updateCarriedLeftVisible(int weaptype) const;
|
||||
|
||||
public:
|
||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||
|
@ -312,8 +299,6 @@ public:
|
|||
|
||||
void playSwishSound(float attackStrength);
|
||||
};
|
||||
|
||||
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
||||
}
|
||||
|
||||
#endif /* GAME_MWMECHANICS_CHARACTER_HPP */
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "npcstats.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "aifollow.hpp"
|
||||
#include "weapontype.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -826,8 +827,9 @@ namespace MWMechanics
|
|||
bool isProjectile = false;
|
||||
if (item.getTypeName() == typeid(ESM::Weapon).name())
|
||||
{
|
||||
const ESM::Weapon* ref = item.get<ESM::Weapon>()->mBase;
|
||||
isProjectile = ref->mData.mType >= ESM::Weapon::MarksmanThrown;
|
||||
int type = item.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(type)->mWeaponClass;
|
||||
isProjectile = (weapclass == ESM::WeaponType::Thrown || weapclass == ESM::WeaponType::Ranged);
|
||||
}
|
||||
int type = enchantment->mData.mType;
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#include "creaturestats.hpp"
|
||||
#include "spellcasting.hpp"
|
||||
#include "weapontype.hpp"
|
||||
#include "combat.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -379,7 +381,7 @@ namespace MWMechanics
|
|||
|
||||
case ESM::MagicEffect::BoundLongbow:
|
||||
// AI should not summon the bow if there is no suitable ammo.
|
||||
if (rateAmmo(actor, enemy, ESM::Weapon::Arrow) <= 0.f)
|
||||
if (rateAmmo(actor, enemy, getWeaponType(ESM::Weapon::MarksmanBow)->mAmmoType) <= 0.f)
|
||||
return 0.f;
|
||||
break;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "aicombataction.hpp"
|
||||
#include "spellpriority.hpp"
|
||||
#include "spellcasting.hpp"
|
||||
#include "weapontype.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
|
@ -34,14 +35,15 @@ namespace MWMechanics
|
|||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
|
||||
|
||||
if (type == -1 && (weapon->mData.mType == ESM::Weapon::Arrow || weapon->mData.mType == ESM::Weapon::Bolt))
|
||||
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(weapon->mData.mType)->mWeaponClass;
|
||||
if (type == -1 && weapclass == ESM::WeaponType::Ammo)
|
||||
return 0.f;
|
||||
|
||||
float rating=0.f;
|
||||
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat();
|
||||
float ratingMult = fAIMeleeWeaponMult;
|
||||
|
||||
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow && weapon->mData.mType <= ESM::Weapon::MarksmanThrown)
|
||||
if (weapclass != ESM::WeaponType::Melee)
|
||||
{
|
||||
// Underwater ranged combat is impossible
|
||||
if (world->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)
|
||||
|
@ -59,11 +61,11 @@ namespace MWMechanics
|
|||
const float chop = (weapon->mData.mChop[0] + weapon->mData.mChop[1]) / 2.f;
|
||||
// We need to account for the fact that thrown weapons have 2x real damage applied to the target
|
||||
// as they're both the weapon and the ammo of the hit
|
||||
if (weapon->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
if (weapclass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
rating = chop * 2;
|
||||
}
|
||||
else if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||
else if (weapclass != ESM::WeaponType::Melee)
|
||||
{
|
||||
rating = chop;
|
||||
}
|
||||
|
@ -76,24 +78,28 @@ namespace MWMechanics
|
|||
|
||||
adjustWeaponDamage(rating, item, actor);
|
||||
|
||||
if (weapon->mData.mType != ESM::Weapon::MarksmanBow && weapon->mData.mType != ESM::Weapon::MarksmanCrossbow)
|
||||
if (weapclass != ESM::WeaponType::Ranged)
|
||||
{
|
||||
resistNormalWeapon(enemy, actor, item, rating);
|
||||
applyWerewolfDamageMult(enemy, item, rating);
|
||||
}
|
||||
else if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
|
||||
else
|
||||
{
|
||||
if (arrowRating <= 0.f)
|
||||
rating = 0.f;
|
||||
else
|
||||
rating += arrowRating;
|
||||
}
|
||||
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
if (boltRating <= 0.f)
|
||||
rating = 0.f;
|
||||
else
|
||||
rating += boltRating;
|
||||
int ammotype = MWMechanics::getWeaponType(weapon->mData.mType)->mAmmoType;
|
||||
if (ammotype == ESM::Weapon::Arrow)
|
||||
{
|
||||
if (arrowRating <= 0.f)
|
||||
rating = 0.f;
|
||||
else
|
||||
rating += arrowRating;
|
||||
}
|
||||
else if (ammotype == ESM::Weapon::Bolt)
|
||||
{
|
||||
if (boltRating <= 0.f)
|
||||
rating = 0.f;
|
||||
else
|
||||
rating += boltRating;
|
||||
}
|
||||
}
|
||||
|
||||
if (!weapon->mEnchant.empty())
|
||||
|
@ -104,7 +110,7 @@ namespace MWMechanics
|
|||
int castCost = getEffectiveEnchantmentCastCost(static_cast<float>(enchantment->mData.mCost), actor);
|
||||
float charge = item.getCellRef().getEnchantmentCharge();
|
||||
|
||||
if (charge == -1 || charge >= castCost || weapon->mData.mType >= ESM::Weapon::MarksmanThrown)
|
||||
if (charge == -1 || charge >= castCost || weapclass == ESM::WeaponType::Thrown || weapclass == ESM::WeaponType::Ammo)
|
||||
rating += rateEffects(enchantment->mEffects, actor, enemy);
|
||||
}
|
||||
}
|
||||
|
@ -126,13 +132,13 @@ namespace MWMechanics
|
|||
float chance = getHitChance(actor, enemy, value) / 100.f;
|
||||
rating *= std::min(1.f, std::max(0.01f, chance));
|
||||
|
||||
if (weapon->mData.mType < ESM::Weapon::Arrow)
|
||||
if (weapclass != ESM::WeaponType::Ammo)
|
||||
rating *= weapon->mData.mSpeed;
|
||||
|
||||
return rating * ratingMult;
|
||||
}
|
||||
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, MWWorld::Ptr &bestAmmo, ESM::Weapon::Type ammoType)
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, MWWorld::Ptr &bestAmmo, int ammoType)
|
||||
{
|
||||
float bestAmmoRating = 0.f;
|
||||
if (!actor.getClass().hasInventoryStore(actor))
|
||||
|
@ -153,7 +159,7 @@ namespace MWMechanics
|
|||
return bestAmmoRating;
|
||||
}
|
||||
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, ESM::Weapon::Type ammoType)
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, int ammoType)
|
||||
{
|
||||
MWWorld::Ptr emptyPtr;
|
||||
return rateAmmo(actor, enemy, emptyPtr, ammoType);
|
||||
|
@ -175,8 +181,8 @@ namespace MWMechanics
|
|||
float bonusDamage = 0.f;
|
||||
|
||||
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
|
||||
|
||||
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
||||
int type = esmWeap->mData.mType;
|
||||
if (getWeaponType(type)->mWeaponClass != ESM::WeaponType::Melee)
|
||||
{
|
||||
if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy))
|
||||
{
|
||||
|
|
|
@ -10,8 +10,8 @@ namespace MWMechanics
|
|||
float rateWeapon (const MWWorld::Ptr& item, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy,
|
||||
int type=-1, float arrowRating=0.f, float boltRating=0.f);
|
||||
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, MWWorld::Ptr &bestAmmo, ESM::Weapon::Type ammoType);
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, ESM::Weapon::Type ammoType);
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, MWWorld::Ptr &bestAmmo, int ammoType);
|
||||
float rateAmmo(const MWWorld::Ptr &actor, const MWWorld::Ptr &enemy, int ammoType);
|
||||
|
||||
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
||||
}
|
||||
|
|
53
apps/openmw/mwmechanics/weapontype.cpp
Normal file
53
apps/openmw/mwmechanics/weapontype.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "weapontype.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
static const ESM::WeaponType *sWeaponTypeListEnd = &sWeaponTypeList[sizeof(sWeaponTypeList)/sizeof(sWeaponTypeList[0])];
|
||||
|
||||
MWWorld::ContainerStoreIterator getActiveWeapon(MWWorld::Ptr actor, int *weaptype)
|
||||
{
|
||||
MWWorld::InventoryStore &inv = actor.getClass().getInventoryStore(actor);
|
||||
CreatureStats &stats = actor.getClass().getCreatureStats(actor);
|
||||
if(stats.getDrawState() == MWMechanics::DrawState_Spell)
|
||||
{
|
||||
*weaptype = ESM::Weapon::Spell;
|
||||
return inv.end();
|
||||
}
|
||||
|
||||
if(stats.getDrawState() == MWMechanics::DrawState_Weapon)
|
||||
{
|
||||
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon == inv.end())
|
||||
*weaptype = ESM::Weapon::HandToHand;
|
||||
else
|
||||
{
|
||||
const std::string &type = weapon->getTypeName();
|
||||
if(type == typeid(ESM::Weapon).name())
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||
*weaptype = ref->mBase->mData.mType;
|
||||
}
|
||||
else if (type == typeid(ESM::Lockpick).name() || type == typeid(ESM::Probe).name())
|
||||
*weaptype = ESM::Weapon::PickProbe;
|
||||
}
|
||||
|
||||
return weapon;
|
||||
}
|
||||
|
||||
return inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
}
|
||||
|
||||
const ESM::WeaponType* getWeaponType(const int weaponType)
|
||||
{
|
||||
std::map<int, ESM::WeaponType>::const_iterator found = sWeaponTypeList.find(weaponType);
|
||||
if (found == sWeaponTypeList.end())
|
||||
{
|
||||
// Use one-handed short blades as fallback
|
||||
return &sWeaponTypeList[0];
|
||||
}
|
||||
|
||||
return &found->second;
|
||||
}
|
||||
}
|
271
apps/openmw/mwmechanics/weapontype.hpp
Normal file
271
apps/openmw/mwmechanics/weapontype.hpp
Normal file
|
@ -0,0 +1,271 @@
|
|||
#ifndef GAME_MWMECHANICS_WEAPONTYPE_H
|
||||
#define GAME_MWMECHANICS_WEAPONTYPE_H
|
||||
|
||||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "creaturestats.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
static std::map<int, ESM::WeaponType> sWeaponTypeList =
|
||||
{
|
||||
{
|
||||
ESM::Weapon::None,
|
||||
{
|
||||
/* short group */ "",
|
||||
/* long group */ "",
|
||||
/* sound ID */ "",
|
||||
/* attach bone */ "",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::HandToHand,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::PickProbe,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "pickprobe",
|
||||
/* sound ID */ "",
|
||||
/* attach bone */ "",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::Security,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::Spell,
|
||||
{
|
||||
/* short group */ "spell",
|
||||
/* long group */ "spellcast",
|
||||
/* sound ID */ "",
|
||||
/* attach bone */ "",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::HandToHand,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::HandToHand,
|
||||
{
|
||||
/* short group */ "hh",
|
||||
/* long group */ "handtohand",
|
||||
/* sound ID */ "",
|
||||
/* attach bone */ "",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::HandToHand,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::ShortBladeOneHand,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "weapononehand",
|
||||
/* sound ID */ "Item Weapon Shortblade",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 ShortBladeOneHand",
|
||||
/* usage skill */ ESM::Skill::ShortBlade,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::LongBladeOneHand,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "weapononehand",
|
||||
/* sound ID */ "Item Weapon Longblade",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 LongBladeOneHand",
|
||||
/* usage skill */ ESM::Skill::LongBlade,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::BluntOneHand,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "weapononehand",
|
||||
/* sound ID */ "Item Weapon Blunt",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 BluntOneHand",
|
||||
/* usage skill */ ESM::Skill::BluntWeapon,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::AxeOneHand,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "weapononehand",
|
||||
/* sound ID */ "Item Weapon Blunt",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 LongBladeOneHand",
|
||||
/* usage skill */ ESM::Skill::Axe,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::LongBladeTwoHand,
|
||||
{
|
||||
/* short group */ "2c",
|
||||
/* long group */ "weapontwohand",
|
||||
/* sound ID */ "Item Weapon Longblade",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 LongBladeTwoClose",
|
||||
/* usage skill */ ESM::Skill::LongBlade,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::AxeTwoHand,
|
||||
{
|
||||
/* short group */ "2c",
|
||||
/* long group */ "weapontwohand",
|
||||
/* sound ID */ "Item Weapon Blunt",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 AxeTwoClose",
|
||||
/* usage skill */ ESM::Skill::Axe,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::BluntTwoClose,
|
||||
{
|
||||
/* short group */ "2c",
|
||||
/* long group */ "weapontwohand",
|
||||
/* sound ID */ "Item Weapon Blunt",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 BluntTwoClose",
|
||||
/* usage skill */ ESM::Skill::BluntWeapon,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::BluntTwoWide,
|
||||
{
|
||||
/* short group */ "2w",
|
||||
/* long group */ "weapontwowide",
|
||||
/* sound ID */ "Item Weapon Blunt",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 BluntTwoWide",
|
||||
/* usage skill */ ESM::Skill::BluntWeapon,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::SpearTwoWide,
|
||||
{
|
||||
/* short group */ "2w",
|
||||
/* long group */ "weapontwowide",
|
||||
/* sound ID */ "Item Weapon Spear",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 SpearTwoWide",
|
||||
/* usage skill */ ESM::Skill::Spear,
|
||||
/* weapon class*/ ESM::WeaponType::Melee,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::MarksmanBow,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "bowandarrow",
|
||||
/* sound ID */ "Item Weapon Bow",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 MarksmanBow",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
/* weapon class*/ ESM::WeaponType::Ranged,
|
||||
/* ammo type */ ESM::Weapon::Arrow,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::MarksmanCrossbow,
|
||||
{
|
||||
/* short group */ "crossbow",
|
||||
/* long group */ "crossbow",
|
||||
/* sound ID */ "Item Weapon Crossbow",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 MarksmanCrossbow",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
/* weapon class*/ ESM::WeaponType::Ranged,
|
||||
/* ammo type */ ESM::Weapon::Bolt,
|
||||
/* flags */ ESM::WeaponType::HasHealth|ESM::WeaponType::TwoHanded
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::MarksmanThrown,
|
||||
{
|
||||
/* short group */ "1h",
|
||||
/* long group */ "throwweapon",
|
||||
/* sound ID */ "Item Weapon Blunt",
|
||||
/* attach bone */ "Weapon Bone",
|
||||
/* sheath bone */ "Bip01 MarksmanThrown",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
/* weapon class*/ ESM::WeaponType::Thrown,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::Arrow,
|
||||
{
|
||||
/* short group */ "",
|
||||
/* long group */ "",
|
||||
/* sound ID */ "Item Weapon Ammo",
|
||||
/* attach bone */ "ArrowBone",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
/* weapon class*/ ESM::WeaponType::Ammo,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ 0
|
||||
}
|
||||
},
|
||||
{
|
||||
ESM::Weapon::Bolt,
|
||||
{
|
||||
/* short group */ "",
|
||||
/* long group */ "",
|
||||
/* sound ID */ "Item Weapon Ammo",
|
||||
/* attach bone */ "ArrowBone",
|
||||
/* sheath bone */ "",
|
||||
/* usage skill */ ESM::Skill::Marksman,
|
||||
/* weapon class*/ ESM::WeaponType::Ammo,
|
||||
/* ammo type */ ESM::Weapon::None,
|
||||
/* flags */ 0
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MWWorld::ContainerStoreIterator getActiveWeapon(MWWorld::Ptr actor, int *weaptype);
|
||||
|
||||
const ESM::WeaponType* getWeaponType(const int weaponType);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -28,6 +28,7 @@
|
|||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "vismask.hpp"
|
||||
|
||||
|
@ -51,8 +52,6 @@ ActorAnimation::ActorAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group>
|
|||
|
||||
// Make sure we cleaned object from effects, just in cast if we re-use node
|
||||
removeEffects();
|
||||
|
||||
mWeaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
||||
}
|
||||
|
||||
ActorAnimation::~ActorAnimation()
|
||||
|
@ -84,7 +83,7 @@ PartHolderPtr ActorAnimation::getWeaponPart(const std::string& model, const std:
|
|||
return PartHolderPtr(new PartHolder(instance));
|
||||
}
|
||||
|
||||
osg::Group* ActorAnimation::getBoneByName(std::string boneName)
|
||||
osg::Group* ActorAnimation::getBoneByName(const std::string& boneName)
|
||||
{
|
||||
if (!mObjectRoot)
|
||||
return nullptr;
|
||||
|
@ -105,93 +104,13 @@ std::string ActorAnimation::getHolsteredWeaponBoneName(const MWWorld::ConstPtr&
|
|||
if(type == typeid(ESM::Weapon).name())
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon.get<ESM::Weapon>();
|
||||
ESM::Weapon::Type weaponType = (ESM::Weapon::Type)ref->mBase->mData.mType;
|
||||
return getHolsteredWeaponBoneName(weaponType);
|
||||
int weaponType = ref->mBase->mData.mType;
|
||||
return MWMechanics::getWeaponType(weaponType)->mSheathingBone;
|
||||
}
|
||||
|
||||
return boneName;
|
||||
}
|
||||
|
||||
std::string ActorAnimation::getHolsteredWeaponBoneName(const unsigned int weaponType)
|
||||
{
|
||||
std::string boneName;
|
||||
|
||||
switch(weaponType)
|
||||
{
|
||||
case ESM::Weapon::ShortBladeOneHand:
|
||||
boneName = "Bip01 ShortBladeOneHand";
|
||||
break;
|
||||
case ESM::Weapon::LongBladeOneHand:
|
||||
boneName = "Bip01 LongBladeOneHand";
|
||||
break;
|
||||
case ESM::Weapon::BluntOneHand:
|
||||
boneName = "Bip01 BluntOneHand";
|
||||
break;
|
||||
case ESM::Weapon::AxeOneHand:
|
||||
boneName = "Bip01 LongBladeOneHand";
|
||||
break;
|
||||
case ESM::Weapon::LongBladeTwoHand:
|
||||
boneName = "Bip01 LongBladeTwoClose";
|
||||
break;
|
||||
case ESM::Weapon::BluntTwoClose:
|
||||
boneName = "Bip01 BluntTwoClose";
|
||||
break;
|
||||
case ESM::Weapon::AxeTwoHand:
|
||||
boneName = "Bip01 AxeTwoClose";
|
||||
break;
|
||||
case ESM::Weapon::BluntTwoWide:
|
||||
boneName = "Bip01 BluntTwoWide";
|
||||
break;
|
||||
case ESM::Weapon::SpearTwoWide:
|
||||
boneName = "Bip01 SpearTwoWide";
|
||||
break;
|
||||
case ESM::Weapon::MarksmanBow:
|
||||
boneName = "Bip01 MarksmanBow";
|
||||
break;
|
||||
case ESM::Weapon::MarksmanCrossbow:
|
||||
boneName = "Bip01 MarksmanCrossbow";
|
||||
break;
|
||||
case ESM::Weapon::MarksmanThrown:
|
||||
boneName = "Bip01 MarksmanThrown";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return boneName;
|
||||
}
|
||||
|
||||
void ActorAnimation::injectWeaponBones()
|
||||
{
|
||||
if (!mResourceSystem->getVFS()->exists("meshes\\xbase_anim_sh.nif"))
|
||||
{
|
||||
mWeaponSheathing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> sheathSkeleton = mResourceSystem->getSceneManager()->getInstance("meshes\\xbase_anim_sh.nif");
|
||||
|
||||
for (unsigned int type=0; type<=ESM::Weapon::MarksmanThrown; ++type)
|
||||
{
|
||||
const std::string holsteredBoneName = getHolsteredWeaponBoneName(type);
|
||||
|
||||
SceneUtil::FindByNameVisitor findVisitor (holsteredBoneName);
|
||||
sheathSkeleton->accept(findVisitor);
|
||||
osg::ref_ptr<osg::Node> sheathNode = findVisitor.mFoundNode;
|
||||
|
||||
if (sheathNode && sheathNode.get()->getNumParents())
|
||||
{
|
||||
osg::Group* sheathParent = getBoneByName(sheathNode.get()->getParent(0)->getName());
|
||||
|
||||
if (sheathParent)
|
||||
{
|
||||
sheathNode.get()->getParent(0)->removeChild(sheathNode);
|
||||
sheathParent->addChild(sheathNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActorAnimation::resetControllers(osg::Node* node)
|
||||
{
|
||||
if (node == nullptr)
|
||||
|
@ -205,7 +124,8 @@ void ActorAnimation::resetControllers(osg::Node* node)
|
|||
|
||||
void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||
{
|
||||
if (!mWeaponSheathing)
|
||||
static const bool weaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
||||
if (!weaponSheathing)
|
||||
return;
|
||||
|
||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||
|
@ -219,7 +139,8 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
|||
return;
|
||||
|
||||
// Since throwing weapons stack themselves, do not show such weapon itself
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
if (MWMechanics::getWeaponType(type)->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
showHolsteredWeapons = false;
|
||||
|
||||
std::string mesh = weapon->getClass().getModel(*weapon);
|
||||
|
@ -279,7 +200,8 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
|||
|
||||
void ActorAnimation::updateQuiver()
|
||||
{
|
||||
if (!mWeaponSheathing)
|
||||
static const bool weaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
||||
if (!weaponSheathing)
|
||||
return;
|
||||
|
||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||
|
@ -303,10 +225,12 @@ void ActorAnimation::updateQuiver()
|
|||
bool suitableAmmo = false;
|
||||
MWWorld::ConstContainerStoreIterator ammo = weapon;
|
||||
unsigned int ammoCount = 0;
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
const auto& weaponType = MWMechanics::getWeaponType(type);
|
||||
if (weaponType->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
ammoCount = ammo->getRefData().getCount();
|
||||
osg::Group* throwingWeaponNode = getBoneByName("Weapon Bone");
|
||||
osg::Group* throwingWeaponNode = getBoneByName(weaponType->mAttachBone);
|
||||
if (throwingWeaponNode && throwingWeaponNode->getNumChildren())
|
||||
ammoCount--;
|
||||
|
||||
|
@ -323,10 +247,7 @@ void ActorAnimation::updateQuiver()
|
|||
if (arrowAttached)
|
||||
ammoCount--;
|
||||
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
suitableAmmo = ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt;
|
||||
else if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanBow)
|
||||
suitableAmmo = ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow;
|
||||
suitableAmmo = ammo->get<ESM::Weapon>()->mBase->mData.mType == weaponType->mAmmoType;
|
||||
}
|
||||
|
||||
if (!suitableAmmo)
|
||||
|
@ -382,7 +303,8 @@ void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/)
|
|||
return;
|
||||
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.end();
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
if (MWMechanics::getWeaponType(type)->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
ammo = weapon;
|
||||
else
|
||||
ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
|
@ -415,7 +337,8 @@ void ActorAnimation::itemRemoved(const MWWorld::ConstPtr& item, int /*count*/)
|
|||
return;
|
||||
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.end();
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
if (MWMechanics::getWeaponType(type)->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
ammo = weapon;
|
||||
else
|
||||
ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
|
|
|
@ -40,13 +40,10 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener
|
|||
virtual bool isArrowAttached() const { return false; }
|
||||
|
||||
protected:
|
||||
bool mWeaponSheathing;
|
||||
osg::Group* getBoneByName(std::string boneName);
|
||||
osg::Group* getBoneByName(const std::string& boneName);
|
||||
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
||||
virtual void injectWeaponBones();
|
||||
virtual void updateQuiver();
|
||||
virtual std::string getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon);
|
||||
virtual std::string getHolsteredWeaponBoneName(const unsigned int weaponType);
|
||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename, bool enchantedGlow, osg::Vec4f* glowColor);
|
||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename)
|
||||
{
|
||||
|
|
|
@ -234,6 +234,25 @@ namespace
|
|||
std::vector<std::pair<osg::Node*, osg::Group*> > mToRemove;
|
||||
};
|
||||
|
||||
class GetExtendedBonesVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
GetExtendedBonesVisitor()
|
||||
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
|
||||
{
|
||||
}
|
||||
|
||||
void apply(osg::Node& node)
|
||||
{
|
||||
if (SceneUtil::hasUserDescription(&node, "CustomBone"))
|
||||
mFoundBones.emplace_back(&node, node.getParent(0));
|
||||
|
||||
traverse(node);
|
||||
}
|
||||
|
||||
std::vector<std::pair<osg::Node*, osg::Group*> > mFoundBones;
|
||||
};
|
||||
|
||||
class RemoveFinishedCallbackVisitor : public RemoveVisitor
|
||||
{
|
||||
public:
|
||||
|
@ -1336,8 +1355,66 @@ namespace MWRender
|
|||
state->second.mLoopingEnabled = enabled;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Node> getModelInstance(Resource::SceneManager* sceneMgr, const std::string& model, bool baseonly)
|
||||
void loadBonesFromFile(osg::ref_ptr<osg::Node>& baseNode, const std::string &model, Resource::ResourceSystem* resourceSystem)
|
||||
{
|
||||
const osg::Node* node = resourceSystem->getSceneManager()->getTemplate(model).get();
|
||||
osg::ref_ptr<osg::Node> sheathSkeleton (const_cast<osg::Node*>(node)); // const-trickery required because there is no const version of NodeVisitor
|
||||
|
||||
GetExtendedBonesVisitor getBonesVisitor;
|
||||
sheathSkeleton->accept(getBonesVisitor);
|
||||
for (auto& nodePair : getBonesVisitor.mFoundBones)
|
||||
{
|
||||
SceneUtil::FindByNameVisitor findVisitor (nodePair.second->getName());
|
||||
baseNode->accept(findVisitor);
|
||||
|
||||
osg::Group* sheathParent = findVisitor.mFoundNode;
|
||||
if (sheathParent)
|
||||
{
|
||||
osg::Node* copy = osg::clone(nodePair.first, osg::CopyOp::DEEP_COPY_NODES);
|
||||
sheathParent->addChild(copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void injectCustomBones(osg::ref_ptr<osg::Node>& node, const std::string& model, Resource::ResourceSystem* resourceSystem)
|
||||
{
|
||||
const std::map<std::string, VFS::File*>& index = resourceSystem->getVFS()->getIndex();
|
||||
|
||||
std::string animationPath = model;
|
||||
if (animationPath.find("meshes") == 0)
|
||||
{
|
||||
animationPath.replace(0, 6, "animations");
|
||||
}
|
||||
animationPath.replace(animationPath.size()-4, 4, "/");
|
||||
|
||||
resourceSystem->getVFS()->normalizeFilename(animationPath);
|
||||
|
||||
std::map<std::string, VFS::File*>::const_iterator found = index.lower_bound(animationPath);
|
||||
while (found != index.end())
|
||||
{
|
||||
const std::string& name = found->first;
|
||||
if (name.size() >= animationPath.size() && name.substr(0, animationPath.size()) == animationPath)
|
||||
{
|
||||
size_t pos = name.find_last_of('.');
|
||||
if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".nif") == 0)
|
||||
loadBonesFromFile(node, name, resourceSystem);
|
||||
}
|
||||
else
|
||||
break;
|
||||
++found;
|
||||
}
|
||||
}
|
||||
|
||||
enum InjectType
|
||||
{
|
||||
None,
|
||||
Model,
|
||||
ModelWithFallback
|
||||
};
|
||||
|
||||
osg::ref_ptr<osg::Node> getModelInstance(Resource::ResourceSystem* resourceSystem, const std::string& model, bool baseonly, InjectType inject)
|
||||
{
|
||||
Resource::SceneManager* sceneMgr = resourceSystem->getSceneManager();
|
||||
if (baseonly)
|
||||
{
|
||||
typedef std::map<std::string, osg::ref_ptr<osg::Node> > Cache;
|
||||
|
@ -1347,6 +1424,12 @@ namespace MWRender
|
|||
{
|
||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||
|
||||
if (inject == InjectType::ModelWithFallback)
|
||||
injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem);
|
||||
|
||||
if (inject != InjectType::None)
|
||||
injectCustomBones(created, model, resourceSystem);
|
||||
|
||||
SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
|
||||
created->accept(removeDrawableVisitor);
|
||||
removeDrawableVisitor.remove();
|
||||
|
@ -1359,7 +1442,17 @@ namespace MWRender
|
|||
return sceneMgr->createInstance(found->second);
|
||||
}
|
||||
else
|
||||
return sceneMgr->getInstance(model);
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = sceneMgr->getInstance(model);
|
||||
|
||||
if (inject == InjectType::ModelWithFallback)
|
||||
injectCustomBones(created, "meshes\\xbase_anim.nif", resourceSystem);
|
||||
|
||||
if (inject != InjectType::None)
|
||||
injectCustomBones(created, model, resourceSystem);
|
||||
|
||||
return created;
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature)
|
||||
|
@ -1381,9 +1474,18 @@ namespace MWRender
|
|||
mAccumRoot = nullptr;
|
||||
mAccumCtrl = nullptr;
|
||||
|
||||
static const bool useAdditionalSources = Settings::Manager::getBool ("use additional anim sources", "Game");
|
||||
InjectType inject = useAdditionalSources && mPtr.getClass().isActor() ? InjectType::Model : InjectType::None;
|
||||
if (inject != InjectType::None && isCreature)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Creature> *ref = mPtr.get<ESM::Creature>();
|
||||
if(ref->mBase->mFlags & ESM::Creature::Bipedal)
|
||||
inject = InjectType::ModelWithFallback;
|
||||
}
|
||||
|
||||
if (!forceskeleton)
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem->getSceneManager(), model, baseonly);
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject);
|
||||
mInsert->addChild(created);
|
||||
mObjectRoot = created->asGroup();
|
||||
if (!mObjectRoot)
|
||||
|
@ -1399,7 +1501,7 @@ namespace MWRender
|
|||
}
|
||||
else
|
||||
{
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem->getSceneManager(), model, baseonly);
|
||||
osg::ref_ptr<osg::Node> created = getModelInstance(mResourceSystem, model, baseonly, inject);
|
||||
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
|
||||
if (!skel)
|
||||
{
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "../mwworld/inventorystore.hpp"
|
||||
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "npcanimation.hpp"
|
||||
#include "vismask.hpp"
|
||||
|
@ -290,55 +291,25 @@ namespace MWRender
|
|||
|
||||
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
|
||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
std::string groupname;
|
||||
std::string groupname = "inventoryhandtohand";
|
||||
bool showCarriedLeft = true;
|
||||
if(iter == inv.end())
|
||||
groupname = "inventoryhandtohand";
|
||||
else
|
||||
if(iter != inv.end())
|
||||
{
|
||||
const std::string &typeName = iter->getTypeName();
|
||||
if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name())
|
||||
groupname = "inventoryweapononehand";
|
||||
else if(typeName == typeid(ESM::Weapon).name())
|
||||
groupname = "inventoryweapononehand";
|
||||
if(iter->getTypeName() == typeid(ESM::Weapon).name())
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>();
|
||||
|
||||
int type = ref->mBase->mData.mType;
|
||||
if(type == ESM::Weapon::ShortBladeOneHand ||
|
||||
type == ESM::Weapon::LongBladeOneHand ||
|
||||
type == ESM::Weapon::BluntOneHand ||
|
||||
type == ESM::Weapon::AxeOneHand ||
|
||||
type == ESM::Weapon::MarksmanThrown)
|
||||
{
|
||||
groupname = "inventoryweapononehand";
|
||||
}
|
||||
else if(type == ESM::Weapon::MarksmanCrossbow ||
|
||||
type == ESM::Weapon::MarksmanBow)
|
||||
{
|
||||
groupname = "inventoryweapononehand";
|
||||
showCarriedLeft = false;
|
||||
}
|
||||
else if(type == ESM::Weapon::LongBladeTwoHand ||
|
||||
type == ESM::Weapon::BluntTwoClose ||
|
||||
type == ESM::Weapon::AxeTwoHand)
|
||||
{
|
||||
groupname = "inventoryweapontwohand";
|
||||
showCarriedLeft = false;
|
||||
}
|
||||
else if(type == ESM::Weapon::BluntTwoWide ||
|
||||
type == ESM::Weapon::SpearTwoWide)
|
||||
{
|
||||
groupname = "inventoryweapontwowide";
|
||||
showCarriedLeft = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
groupname = "inventoryhandtohand";
|
||||
showCarriedLeft = false;
|
||||
}
|
||||
const ESM::WeaponType* weaponInfo = MWMechanics::getWeaponType(type);
|
||||
showCarriedLeft = !(weaponInfo->mFlags & ESM::WeaponType::TwoHanded);
|
||||
|
||||
std::string inventoryGroup = weaponInfo->mLongGroup;
|
||||
inventoryGroup = "inventory" + inventoryGroup;
|
||||
|
||||
// We still should use one-handed animation as fallback
|
||||
if (mAnimation->hasAnimation(inventoryGroup))
|
||||
groupname = inventoryGroup;
|
||||
}
|
||||
else
|
||||
groupname = "inventoryhandtohand";
|
||||
}
|
||||
|
||||
mAnimation->showCarriedLeft(showCarriedLeft);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "../mwbase/world.hpp"
|
||||
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
|
||||
namespace MWRender
|
||||
|
@ -50,9 +52,6 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const
|
|||
|
||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||
{
|
||||
if (mWeaponSheathing)
|
||||
injectWeaponBones();
|
||||
|
||||
addAnimSource("meshes\\xbase_anim.nif", model);
|
||||
}
|
||||
addAnimSource(model, model);
|
||||
|
@ -115,7 +114,15 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
|
|||
|
||||
std::string bonename;
|
||||
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
|
||||
bonename = "Weapon Bone";
|
||||
{
|
||||
if(item.getTypeName() == typeid(ESM::Weapon).name())
|
||||
{
|
||||
int type = item.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
bonename = MWMechanics::getWeaponType(type)->mAttachBone;
|
||||
}
|
||||
else
|
||||
bonename = "Weapon Bone";
|
||||
}
|
||||
else
|
||||
bonename = "Shield Bone";
|
||||
|
||||
|
@ -140,8 +147,9 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
|
|||
item.getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
item.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
const ESM::WeaponType* weaponInfo = MWMechanics::getWeaponType(ESM::Weapon::MarksmanCrossbow);
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == weaponInfo->mAmmoType)
|
||||
attachArrow();
|
||||
else
|
||||
mAmmunition.reset();
|
||||
|
@ -197,7 +205,19 @@ osg::Group *CreatureWeaponAnimation::getArrowBone()
|
|||
if (!mWeapon)
|
||||
return nullptr;
|
||||
|
||||
SceneUtil::FindByNameVisitor findVisitor ("ArrowBone");
|
||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||
return nullptr;
|
||||
|
||||
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon == inv.end() || weapon->getTypeName() != typeid(ESM::Weapon).name())
|
||||
return nullptr;
|
||||
|
||||
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
int ammoType = MWMechanics::getWeaponType(type)->mAmmoType;
|
||||
|
||||
SceneUtil::FindByNameVisitor findVisitor (MWMechanics::getWeaponType(ammoType)->mAttachBone);
|
||||
|
||||
mWeapon->getNode()->accept(findVisitor);
|
||||
|
||||
return findVisitor.mFoundNode;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/world.hpp"
|
||||
|
@ -275,7 +276,7 @@ static NpcAnimation::PartBoneMap createPartListMap()
|
|||
result.insert(std::make_pair(ESM::PRT_LLeg, "Left Upper Leg"));
|
||||
result.insert(std::make_pair(ESM::PRT_RPauldron, "Right Clavicle"));
|
||||
result.insert(std::make_pair(ESM::PRT_LPauldron, "Left Clavicle"));
|
||||
result.insert(std::make_pair(ESM::PRT_Weapon, "Weapon Bone"));
|
||||
result.insert(std::make_pair(ESM::PRT_Weapon, "Weapon Bone")); // Fallback. The real node name depends on the current weapon type.
|
||||
result.insert(std::make_pair(ESM::PRT_Tail, "Tail"));
|
||||
return result;
|
||||
}
|
||||
|
@ -318,12 +319,6 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
|||
if(mViewMode == viewMode)
|
||||
return;
|
||||
|
||||
// Disable weapon sheathing in the 1st-person mode
|
||||
if (viewMode == VM_FirstPerson)
|
||||
mWeaponSheathing = false;
|
||||
else
|
||||
mWeaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
||||
|
||||
mViewMode = viewMode;
|
||||
MWBase::Environment::get().getWorld()->scaleObject(mPtr, mPtr.getCellRef().getScale()); // apply race height after view change
|
||||
|
||||
|
@ -485,9 +480,6 @@ void NpcAnimation::updateNpcBase()
|
|||
|
||||
setObjectRoot(smodel, true, true, false);
|
||||
|
||||
if (mWeaponSheathing)
|
||||
injectWeaponBones();
|
||||
|
||||
updateParts();
|
||||
|
||||
if(!is1stPerson)
|
||||
|
@ -745,7 +737,18 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
|
|||
mPartPriorities[type] = priority;
|
||||
try
|
||||
{
|
||||
const std::string& bonename = sPartList.at(type);
|
||||
std::string bonename = sPartList.at(type);
|
||||
if (type == ESM::PRT_Weapon)
|
||||
{
|
||||
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name())
|
||||
{
|
||||
int weaponType = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
bonename = MWMechanics::getWeaponType(weaponType)->mAttachBone;
|
||||
}
|
||||
}
|
||||
|
||||
// PRT_Hair seems to be the only type that breaks consistency and uses a filter that's different from the attachment bone
|
||||
const std::string bonefilter = (type == ESM::PRT_Hair) ? "hair" : bonename;
|
||||
mObjectParts[type] = insertBoundedPart(mesh, bonename, bonefilter, enchantedGlow, glowColor);
|
||||
|
@ -906,8 +909,9 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
|||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
||||
{
|
||||
int ammotype = MWMechanics::getWeaponType(ESM::Weapon::MarksmanCrossbow)->mAmmoType;
|
||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt)
|
||||
if (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ammotype)
|
||||
attachArrow();
|
||||
}
|
||||
}
|
||||
|
@ -972,7 +976,15 @@ osg::Group* NpcAnimation::getArrowBone()
|
|||
if (!part)
|
||||
return nullptr;
|
||||
|
||||
SceneUtil::FindByNameVisitor findVisitor ("ArrowBone");
|
||||
const MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
|
||||
MWWorld::ConstContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||
if(weapon == inv.end() || weapon->getTypeName() != typeid(ESM::Weapon).name())
|
||||
return nullptr;
|
||||
|
||||
int type = weapon->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
int ammoType = MWMechanics::getWeaponType(type)->mAmmoType;
|
||||
|
||||
SceneUtil::FindByNameVisitor findVisitor (MWMechanics::getWeaponType(ammoType)->mAttachBone);
|
||||
part->getNode()->accept(findVisitor);
|
||||
|
||||
return findVisitor.mFoundNode;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "../mwmechanics/creaturestats.hpp"
|
||||
#include "../mwmechanics/combat.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "animation.hpp"
|
||||
#include "rotatecontroller.hpp"
|
||||
|
@ -67,8 +68,10 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
|||
return;
|
||||
if (weaponSlot->getTypeName() != typeid(ESM::Weapon).name())
|
||||
return;
|
||||
int weaponType = weaponSlot->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
if (weaponType == ESM::Weapon::MarksmanThrown)
|
||||
|
||||
int type = weaponSlot->get<ESM::Weapon>()->mBase->mData.mType;
|
||||
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(type)->mWeaponClass;
|
||||
if (weapclass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
std::string soundid = weaponSlot->getClass().getUpSoundId(*weaponSlot);
|
||||
if(!soundid.empty())
|
||||
|
@ -78,7 +81,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
|||
}
|
||||
showWeapon(true);
|
||||
}
|
||||
else if (weaponType == ESM::Weapon::MarksmanBow || weaponType == ESM::Weapon::MarksmanCrossbow)
|
||||
else if (weapclass == ESM::WeaponType::Ranged)
|
||||
{
|
||||
osg::Group* parent = getArrowBone();
|
||||
if (!parent)
|
||||
|
@ -113,7 +116,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
|
|||
|
||||
MWMechanics::applyFatigueLoss(actor, *weapon, attackStrength);
|
||||
|
||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
||||
if (MWMechanics::getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mWeaponClass == ESM::WeaponType::Thrown)
|
||||
{
|
||||
// Thrown weapons get detached now
|
||||
osg::Node* weaponNode = getWeaponNode();
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "../mwmechanics/npcstats.hpp"
|
||||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "esmstore.hpp"
|
||||
#include "class.hpp"
|
||||
|
@ -332,7 +332,7 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
|
|||
|
||||
const ESM::Weapon* esmWeapon = iter->get<ESM::Weapon>()->mBase;
|
||||
|
||||
if (esmWeapon->mData.mType == ESM::Weapon::Arrow || esmWeapon->mData.mType == ESM::Weapon::Bolt)
|
||||
if (MWMechanics::getWeaponType(esmWeapon->mData.mType)->mWeaponClass == ESM::WeaponType::Ammo)
|
||||
continue;
|
||||
|
||||
if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill])
|
||||
|
@ -357,31 +357,21 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
|
|||
}
|
||||
}
|
||||
|
||||
bool isBow = false;
|
||||
bool isCrossbow = false;
|
||||
if (weapon != end())
|
||||
{
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||
ESM::Weapon::Type type = (ESM::Weapon::Type)ref->mBase->mData.mType;
|
||||
|
||||
if (type == ESM::Weapon::MarksmanBow)
|
||||
isBow = true;
|
||||
else if (type == ESM::Weapon::MarksmanCrossbow)
|
||||
isCrossbow = true;
|
||||
}
|
||||
|
||||
if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first)
|
||||
{
|
||||
// Do not equip ranged weapons, if there is no suitable ammo
|
||||
bool hasAmmo = true;
|
||||
if (isBow == true)
|
||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon->get<ESM::Weapon>();
|
||||
int type = ref->mBase->mData.mType;
|
||||
int ammotype = MWMechanics::getWeaponType(type)->mAmmoType;
|
||||
if (ammotype == ESM::Weapon::Arrow)
|
||||
{
|
||||
if (arrow == end())
|
||||
hasAmmo = false;
|
||||
else
|
||||
slots_[Slot_Ammunition] = arrow;
|
||||
}
|
||||
if (isCrossbow == true)
|
||||
else if (ammotype == ESM::Weapon::Bolt)
|
||||
{
|
||||
if (bolt == end())
|
||||
hasAmmo = false;
|
||||
|
@ -406,7 +396,7 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
|
|||
int slot = itemsSlots.first.front();
|
||||
slots_[slot] = weapon;
|
||||
|
||||
if (!isBow && !isCrossbow)
|
||||
if (ammotype == ESM::Weapon::None)
|
||||
slots_[Slot_Ammunition] = end();
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include "../mwmechanics/actorutil.hpp"
|
||||
#include "../mwmechanics/aipackage.hpp"
|
||||
#include "../mwmechanics/weapontype.hpp"
|
||||
|
||||
#include "../mwrender/animation.hpp"
|
||||
#include "../mwrender/vismask.hpp"
|
||||
|
@ -317,7 +318,9 @@ namespace MWWorld
|
|||
state.mIdArrow = projectile.getCellRef().getRefId();
|
||||
state.mCasterHandle = actor;
|
||||
state.mAttackStrength = attackStrength;
|
||||
state.mThrown = projectile.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown;
|
||||
|
||||
int type = projectile.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
state.mThrown = MWMechanics::getWeaponType(type)->mWeaponClass == ESM::WeaponType::Thrown;
|
||||
|
||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
|
||||
MWWorld::Ptr ptr = ref.getPtr();
|
||||
|
@ -604,7 +607,9 @@ namespace MWWorld
|
|||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
|
||||
MWWorld::Ptr ptr = ref.getPtr();
|
||||
model = ptr.getClass().getModel(ptr);
|
||||
state.mThrown = ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown;
|
||||
|
||||
int weaponType = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
||||
state.mThrown = MWMechanics::getWeaponType(weaponType)->mWeaponClass == ESM::WeaponType::Thrown;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
|
|
@ -388,6 +388,30 @@ namespace MWWorld
|
|||
iterator end() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
class Store<ESM::WeaponType> : public StoreBase
|
||||
{
|
||||
std::map<int, ESM::WeaponType> mStatic;
|
||||
|
||||
public:
|
||||
typedef std::map<int, ESM::WeaponType>::const_iterator iterator;
|
||||
|
||||
Store();
|
||||
|
||||
const ESM::WeaponType *search(const int id) const;
|
||||
const ESM::WeaponType *find(const int id) const;
|
||||
|
||||
RecordId load(ESM::ESMReader &esm) { return RecordId(0, false); }
|
||||
|
||||
ESM::WeaponType* insert(const ESM::WeaponType &weaponType);
|
||||
|
||||
void setUp();
|
||||
|
||||
size_t getSize() const;
|
||||
iterator begin() const;
|
||||
iterator end() const;
|
||||
};
|
||||
|
||||
|
||||
} //end namespace
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "loadskil.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
|
||||
|
@ -21,6 +23,10 @@ struct Weapon
|
|||
|
||||
enum Type
|
||||
{
|
||||
PickProbe = -4,
|
||||
HandToHand = -3,
|
||||
Spell = -2,
|
||||
None = -1,
|
||||
ShortBladeOneHand = 0,
|
||||
LongBladeOneHand = 1,
|
||||
LongBladeTwoHand = 2,
|
||||
|
@ -75,5 +81,34 @@ struct Weapon
|
|||
void blank();
|
||||
///< Set record to default state (does not touch the ID).
|
||||
};
|
||||
|
||||
struct WeaponType
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
TwoHanded = 0x01,
|
||||
HasHealth = 0x02
|
||||
};
|
||||
|
||||
enum Class
|
||||
{
|
||||
Melee = 0,
|
||||
Ranged = 1,
|
||||
Thrown = 2,
|
||||
Ammo = 3
|
||||
};
|
||||
|
||||
//std::string mDisplayName; // TODO: will be needed later for editor
|
||||
std::string mShortGroup;
|
||||
std::string mLongGroup;
|
||||
std::string mSoundId;
|
||||
std::string mAttachBone;
|
||||
std::string mSheathingBone;
|
||||
ESM::Skill::SkillEnum mSkill;
|
||||
Class mWeaponClass;
|
||||
int mAmmoType;
|
||||
int mFlags;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -540,6 +540,10 @@ namespace NifOsg
|
|||
// Marker objects. These meshes are only visible in the editor.
|
||||
hasMarkers = true;
|
||||
}
|
||||
else if(sd->string == "BONE")
|
||||
{
|
||||
node->getOrCreateUserDataContainer()->addDescription("CustomBone");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue