mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 21:49:41 +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
|
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
|
aicast aiescort aiface aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
|
||||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
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
|
add_openmw_dir (mwstate
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
#include "../mwrender/renderinginterface.hpp"
|
#include "../mwrender/renderinginterface.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "../mwgui/tooltips.hpp"
|
#include "../mwgui/tooltips.hpp"
|
||||||
|
|
||||||
|
@ -332,21 +333,13 @@ namespace MWClass
|
||||||
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
if(*slot == MWWorld::InventoryStore::Slot_CarriedLeft)
|
||||||
{
|
{
|
||||||
MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ConstContainerStoreIterator weapon = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
|
if(weapon != invStore.end() && weapon->getTypeName() == typeid(ESM::Weapon).name())
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
|
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(3,"");
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair(1,"");
|
return std::make_pair(1,"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
#include "../mwmechanics/combat.hpp"
|
#include "../mwmechanics/combat.hpp"
|
||||||
#include "../mwmechanics/autocalcspell.hpp"
|
#include "../mwmechanics/autocalcspell.hpp"
|
||||||
#include "../mwmechanics/difficultyscaling.hpp"
|
#include "../mwmechanics/difficultyscaling.hpp"
|
||||||
#include "../mwmechanics/character.hpp"
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
|
||||||
#include "../mwworld/ptr.hpp"
|
#include "../mwworld/ptr.hpp"
|
||||||
|
@ -1228,9 +1228,9 @@ namespace MWClass
|
||||||
if (getNpcStats(ptr).isWerewolf()
|
if (getNpcStats(ptr).isWerewolf()
|
||||||
&& getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
|
&& getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run))
|
||||||
{
|
{
|
||||||
MWMechanics::WeaponType weaponType = MWMechanics::WeapType_None;
|
int weaponType = ESM::Weapon::None;
|
||||||
MWMechanics::getActiveWeapon(getCreatureStats(ptr), getInventoryStore(ptr), &weaponType);
|
MWMechanics::getActiveWeapon(ptr, &weaponType);
|
||||||
if (weaponType == MWMechanics::WeapType_None)
|
if (weaponType == ESM::Weapon::None)
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include "../mwphysics/physicssystem.hpp"
|
#include "../mwphysics/physicssystem.hpp"
|
||||||
#include "../mwworld/nullaction.hpp"
|
#include "../mwworld/nullaction.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "../mwgui/tooltips.hpp"
|
#include "../mwgui/tooltips.hpp"
|
||||||
|
|
||||||
#include "../mwrender/objects.hpp"
|
#include "../mwrender/objects.hpp"
|
||||||
|
@ -64,8 +66,9 @@ namespace MWClass
|
||||||
bool Weapon::hasItemHealth (const MWWorld::ConstPtr& ptr) const
|
bool Weapon::hasItemHealth (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
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
|
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
|
std::pair<std::vector<int>, bool> Weapon::getEquipmentSlots (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
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_;
|
std::vector<int> slots_;
|
||||||
bool stack = false;
|
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));
|
slots_.push_back (int (MWWorld::InventoryStore::Slot_Ammunition));
|
||||||
stack = true;
|
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));
|
slots_.push_back (int (MWWorld::InventoryStore::Slot_CarriedRight));
|
||||||
stack = true;
|
stack = true;
|
||||||
|
@ -109,30 +113,9 @@ namespace MWClass
|
||||||
int Weapon::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const
|
int Weapon::getEquipmentSkill (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||||
|
int type = ref->mBase->mData.mType;
|
||||||
|
|
||||||
const int size = 12;
|
return MWMechanics::getWeaponType(type)->mSkill;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Weapon::getValue (const MWWorld::ConstPtr& ptr) const
|
int Weapon::getValue (const MWWorld::ConstPtr& ptr) const
|
||||||
|
@ -152,89 +135,17 @@ namespace MWClass
|
||||||
std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
std::string Weapon::getUpSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||||
|
|
||||||
int type = ref->mBase->mData.mType;
|
int type = ref->mBase->mData.mType;
|
||||||
// Ammo
|
std::string soundId = MWMechanics::getWeaponType(type)->mSoundId;
|
||||||
if (type == 12 || type == 13)
|
return soundId + " Up";
|
||||||
{
|
|
||||||
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 Weapon::getDownSoundId (const MWWorld::ConstPtr& ptr) const
|
std::string Weapon::getDownSoundId (const MWWorld::ConstPtr& ptr) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||||
|
|
||||||
int type = ref->mBase->mData.mType;
|
int type = ref->mBase->mData.mType;
|
||||||
// Ammo
|
std::string soundId = MWMechanics::getWeaponType(type)->mSoundId;
|
||||||
if (type == 12 || type == 13)
|
return soundId + " Down";
|
||||||
{
|
|
||||||
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 Weapon::getInventoryIcon (const MWWorld::ConstPtr& ptr) const
|
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
|
MWGui::ToolTipInfo Weapon::getToolTipInfo (const MWWorld::ConstPtr& ptr, int count) const
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = ptr.get<ESM::Weapon>();
|
||||||
|
const ESM::WeaponType* weaponType = MWMechanics::getWeaponType(ref->mBase->mData.mType);
|
||||||
|
|
||||||
MWGui::ToolTipInfo info;
|
MWGui::ToolTipInfo info;
|
||||||
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
info.caption = ref->mBase->mName + MWGui::ToolTips::getCountString(count);
|
||||||
|
@ -264,37 +176,26 @@ namespace MWClass
|
||||||
std::string text;
|
std::string text;
|
||||||
|
|
||||||
// weapon type & damage
|
// 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} ";
|
text += "\n#{sType} ";
|
||||||
|
|
||||||
static std::map <int, std::pair <std::string, std::string> > mapping;
|
int skill = MWMechanics::getWeaponType(ref->mBase->mData.mType)->mSkill;
|
||||||
if (mapping.empty())
|
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");
|
if (weaponType->mFlags & ESM::WeaponType::TwoHanded)
|
||||||
mapping[ESM::Weapon::LongBladeOneHand] = std::make_pair("sSkillLongblade", "sOneHanded");
|
oneOrTwoHanded = "sTwoHanded";
|
||||||
mapping[ESM::Weapon::LongBladeTwoHand] = std::make_pair("sSkillLongblade", "sTwoHanded");
|
else
|
||||||
mapping[ESM::Weapon::BluntOneHand] = std::make_pair("sSkillBluntweapon", "sOneHanded");
|
oneOrTwoHanded = "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", "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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() +
|
text += store.get<ESM::GameSetting>().find(type)->mValue.getString() +
|
||||||
((oneOrTwoHanded != "") ? ", " + store.get<ESM::GameSetting>().find(oneOrTwoHanded)->mValue.getString() : "");
|
((oneOrTwoHanded != "") ? ", " + store.get<ESM::GameSetting>().find(oneOrTwoHanded)->mValue.getString() : "");
|
||||||
|
|
||||||
// weapon damage
|
// weapon damage
|
||||||
if (ref->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
|
if (weaponType->mWeaponClass == ESM::WeaponType::Thrown)
|
||||||
{
|
{
|
||||||
// Thrown weapons have 2x real damage applied
|
// Thrown weapons have 2x real damage applied
|
||||||
// as they're both the weapon and the ammo
|
// 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[0] * 2))
|
||||||
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[1] * 2));
|
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mChop[1] * 2));
|
||||||
}
|
}
|
||||||
else if (ref->mBase->mData.mType >= ESM::Weapon::MarksmanBow)
|
else if (weaponType->mWeaponClass == ESM::WeaponType::Melee)
|
||||||
{
|
|
||||||
// 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
|
|
||||||
{
|
{
|
||||||
// Chop
|
// Chop
|
||||||
text += "\n#{sChop}: "
|
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[0]))
|
||||||
+ " - " + MWGui::ToolTips::toString(static_cast<int>(ref->mBase->mData.mThrust[1]));
|
+ " - " + 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))
|
if (hasItemHealth(ptr))
|
||||||
|
@ -335,7 +236,7 @@ namespace MWClass
|
||||||
|
|
||||||
const bool verbose = Settings::Manager::getBool("show melee info", "Game");
|
const bool verbose = Settings::Manager::getBool("show melee info", "Game");
|
||||||
// add reach for melee weapon
|
// 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
|
// display value in feet
|
||||||
const float combatDistance = store.get<ESM::GameSetting>().find("fCombatDistance")->mValue.getFloat() * ref->mBase->mData.mReach;
|
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
|
// 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}");
|
text += MWGui::ToolTips::getPercentString(ref->mBase->mData.mSpeed, "#{sAttributeSpeed}");
|
||||||
}
|
}
|
||||||
|
@ -403,13 +304,8 @@ namespace MWClass
|
||||||
if (slots_.first.empty())
|
if (slots_.first.empty())
|
||||||
return std::make_pair (0, "");
|
return std::make_pair (0, "");
|
||||||
|
|
||||||
if(ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::LongBladeTwoHand ||
|
int type = ptr.get<ESM::Weapon>()->mBase->mData.mType;
|
||||||
ptr.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::BluntTwoClose ||
|
if(MWMechanics::getWeaponType(type)->mFlags & ESM::WeaponType::TwoHanded)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
return std::make_pair (2, "");
|
return std::make_pair (2, "");
|
||||||
}
|
}
|
||||||
|
|
|
@ -445,10 +445,9 @@ namespace MWMechanics
|
||||||
|
|
||||||
if (targetClass.hasInventoryStore(target))
|
if (targetClass.hasInventoryStore(target))
|
||||||
{
|
{
|
||||||
MWMechanics::WeaponType weapType = WeapType_None;
|
int weapType = ESM::Weapon::None;
|
||||||
MWWorld::ContainerStoreIterator weaponSlot =
|
MWWorld::ContainerStoreIterator weaponSlot = MWMechanics::getActiveWeapon(target, &weapType);
|
||||||
MWMechanics::getActiveWeapon(targetClass.getCreatureStats(target), targetClass.getInventoryStore(target), &weapType);
|
if (weapType > ESM::Weapon::None)
|
||||||
if (weapType != WeapType_PickProbe && weapType != WeapType_Spell && weapType != WeapType_None && weapType != WeapType_HandToHand)
|
|
||||||
targetWeapon = *weaponSlot;
|
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>();
|
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
|
||||||
|
|
||||||
// get projectile speed (depending on weapon type)
|
// 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 fThrownWeaponMinSpeed = gmst.find("fThrownWeaponMinSpeed")->mValue.getFloat();
|
||||||
static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
|
static float fThrownWeaponMaxSpeed = gmst.find("fThrownWeaponMaxSpeed")->mValue.getFloat();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "combat.hpp"
|
#include "combat.hpp"
|
||||||
#include "weaponpriority.hpp"
|
#include "weaponpriority.hpp"
|
||||||
#include "spellpriority.hpp"
|
#include "spellpriority.hpp"
|
||||||
|
#include "weapontype.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -125,8 +126,7 @@ namespace MWMechanics
|
||||||
}
|
}
|
||||||
|
|
||||||
const ESM::Weapon* weapon = mWeapon.get<ESM::Weapon>()->mBase;
|
const ESM::Weapon* weapon = mWeapon.get<ESM::Weapon>()->mBase;
|
||||||
|
if (MWMechanics::getWeaponType(weapon->mData.mType)->mWeaponClass != ESM::WeaponType::Melee)
|
||||||
if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
|
|
||||||
{
|
{
|
||||||
isRanged = true;
|
isRanged = true;
|
||||||
return fProjectileMaxSpeed;
|
return fProjectileMaxSpeed;
|
||||||
|
@ -194,11 +194,12 @@ namespace MWMechanics
|
||||||
if (rating > bestActionRating)
|
if (rating > bestActionRating)
|
||||||
{
|
{
|
||||||
const ESM::Weapon* weapon = it->get<ESM::Weapon>()->mBase;
|
const ESM::Weapon* weapon = it->get<ESM::Weapon>()->mBase;
|
||||||
|
int ammotype = getWeaponType(weapon->mData.mType)->mAmmoType;
|
||||||
|
|
||||||
MWWorld::Ptr ammo;
|
MWWorld::Ptr ammo;
|
||||||
if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
|
if (ammotype == ESM::Weapon::Arrow)
|
||||||
ammo = bestArrow;
|
ammo = bestArrow;
|
||||||
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
else if (ammotype == ESM::Weapon::Bolt)
|
||||||
ammo = bestBolt;
|
ammo = bestBolt;
|
||||||
|
|
||||||
bestActionRating = rating;
|
bestActionRating = rating;
|
||||||
|
@ -367,7 +368,7 @@ namespace MWMechanics
|
||||||
else if (!activeWeapon.isEmpty())
|
else if (!activeWeapon.isEmpty())
|
||||||
{
|
{
|
||||||
const ESM::Weapon* esmWeap = activeWeapon.get<ESM::Weapon>()->mBase;
|
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();
|
static const float fTargetSpellMaxSpeed = gmst.find("fProjectileMaxSpeed")->mValue.getFloat();
|
||||||
dist = fTargetSpellMaxSpeed;
|
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
|
std::string CharacterController::chooseRandomGroup (const std::string& prefix, int* num) const
|
||||||
{
|
{
|
||||||
int numAnims=0;
|
int numAnims=0;
|
||||||
|
@ -315,7 +288,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
||||||
{
|
{
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
if (mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell)
|
if (mWeaponType > ESM::Weapon::None)
|
||||||
mAnimation->showWeapons(true);
|
mAnimation->showWeapons(true);
|
||||||
}
|
}
|
||||||
else if (mUpperBodyState > UpperCharState_Nothing && mUpperBodyState < UpperCharState_WeapEquiped)
|
else if (mUpperBodyState > UpperCharState_Nothing && mUpperBodyState < UpperCharState_WeapEquiped)
|
||||||
|
@ -347,7 +320,7 @@ void CharacterController::refreshHitRecoilAnims(CharacterState& idle)
|
||||||
idle = CharState_None;
|
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)
|
if (!force && jump == mJumpState && idle == CharState_None)
|
||||||
return;
|
return;
|
||||||
|
@ -357,9 +330,9 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
|
||||||
if (jump != JumpState_None)
|
if (jump != JumpState_None)
|
||||||
{
|
{
|
||||||
jumpAnimName = "jump";
|
jumpAnimName = "jump";
|
||||||
if(weap != sWeaponTypeListEnd)
|
if(!weapShortGroup.empty())
|
||||||
{
|
{
|
||||||
jumpAnimName += weap->shortgroup;
|
jumpAnimName += weapShortGroup;
|
||||||
if(!mAnimation->hasAnimation(jumpAnimName))
|
if(!mAnimation->hasAnimation(jumpAnimName))
|
||||||
{
|
{
|
||||||
jumpmask = MWRender::Animation::BlendMask_LowerBody;
|
jumpmask = MWRender::Animation::BlendMask_LowerBody;
|
||||||
|
@ -371,7 +344,7 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState
|
||||||
idle = CharState_Idle;
|
idle = CharState_Idle;
|
||||||
|
|
||||||
// For crossbow animations use 1h ones as fallback
|
// For crossbow animations use 1h ones as fallback
|
||||||
if (mWeaponType == WeapType_Crossbow)
|
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||||
jumpAnimName += "1h";
|
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)
|
if (movement == mMovementState && idle == mIdleState && !force)
|
||||||
return;
|
return;
|
||||||
|
@ -460,15 +433,15 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
if(movestate != sMovementListEnd)
|
if(movestate != sMovementListEnd)
|
||||||
{
|
{
|
||||||
movementAnimName = movestate->groupname;
|
movementAnimName = movestate->groupname;
|
||||||
if(weap != sWeaponTypeListEnd)
|
if(!weapShortGroup.empty())
|
||||||
{
|
{
|
||||||
std::string::size_type swimpos = movementAnimName.find("swim");
|
std::string::size_type swimpos = movementAnimName.find("swim");
|
||||||
if (swimpos == std::string::npos)
|
if (swimpos == std::string::npos)
|
||||||
{
|
{
|
||||||
if (mWeaponType == WeapType_Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
|
if (mWeaponType == ESM::Weapon::Spell && (movement == CharState_TurnLeft || movement == CharState_TurnRight)) // Spellcasting stance turning is a special case
|
||||||
movementAnimName = weap->shortgroup + movementAnimName;
|
movementAnimName = weapShortGroup + movementAnimName;
|
||||||
else
|
else
|
||||||
movementAnimName += weap->shortgroup;
|
movementAnimName += weapShortGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!mAnimation->hasAnimation(movementAnimName))
|
if(!mAnimation->hasAnimation(movementAnimName))
|
||||||
|
@ -483,7 +456,7 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
idle = CharState_Idle;
|
idle = CharState_Idle;
|
||||||
|
|
||||||
// For crossbow animations use 1h ones as fallback
|
// For crossbow animations use 1h ones as fallback
|
||||||
if (mWeaponType == WeapType_Crossbow)
|
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||||
movementAnimName += "1h";
|
movementAnimName += "1h";
|
||||||
}
|
}
|
||||||
else if (idle == CharState_None)
|
else if (idle == CharState_None)
|
||||||
|
@ -521,13 +494,13 @@ void CharacterController::refreshMovementAnims(const WeaponInfo* weap, Character
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// For crossbow animations use 1h ones as fallback
|
// For crossbow animations use 1h ones as fallback
|
||||||
if (mWeaponType == WeapType_Crossbow)
|
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||||
movementAnimName += "1h";
|
movementAnimName += "1h";
|
||||||
|
|
||||||
movementAnimName.erase(swimpos, 4);
|
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))
|
if(mAnimation->hasAnimation(weapMovementAnimName))
|
||||||
movementAnimName = weapMovementAnimName;
|
movementAnimName = weapMovementAnimName;
|
||||||
else
|
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),
|
// 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
|
// the idle animation should be displayed
|
||||||
|
@ -630,9 +603,9 @@ void CharacterController::refreshIdleAnims(const WeaponInfo* weap, CharacterStat
|
||||||
else if(mIdleState != CharState_None)
|
else if(mIdleState != CharState_None)
|
||||||
{
|
{
|
||||||
idleGroup = "idle";
|
idleGroup = "idle";
|
||||||
if(weap != sWeaponTypeListEnd)
|
if(!weapShortGroup.empty())
|
||||||
{
|
{
|
||||||
idleGroup += weap->shortgroup;
|
idleGroup += weapShortGroup;
|
||||||
if(!mAnimation->hasAnimation(idleGroup))
|
if(!mAnimation->hasAnimation(idleGroup))
|
||||||
idleGroup = "idle";
|
idleGroup = "idle";
|
||||||
|
|
||||||
|
@ -669,9 +642,9 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
if (mPtr.getClass().isActor())
|
if (mPtr.getClass().isActor())
|
||||||
refreshHitRecoilAnims(idle);
|
refreshHitRecoilAnims(idle);
|
||||||
|
|
||||||
const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType));
|
std::string weap;
|
||||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
weap = sWeaponTypeListEnd;
|
weap = getWeaponType(mWeaponType)->mShortGroup;
|
||||||
|
|
||||||
refreshJumpAnims(weap, jump, idle, force);
|
refreshJumpAnims(weap, jump, idle, force);
|
||||||
refreshMovementAnims(weap, movement, idle, force);
|
refreshMovementAnims(weap, movement, idle, force);
|
||||||
|
@ -680,77 +653,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
|
||||||
refreshIdleAnims(weap, idle, force);
|
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)
|
void CharacterController::playDeath(float startpoint, CharacterState death)
|
||||||
{
|
{
|
||||||
// Make sure the character was swimming upon death for forward-compatibility
|
// 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)
|
, mHitState(CharState_None)
|
||||||
, mUpperBodyState(UpperCharState_Nothing)
|
, mUpperBodyState(UpperCharState_Nothing)
|
||||||
, mJumpState(JumpState_None)
|
, mJumpState(JumpState_None)
|
||||||
, mWeaponType(WeapType_None)
|
, mWeaponType(ESM::Weapon::None)
|
||||||
, mAttackStrength(0.f)
|
, mAttackStrength(0.f)
|
||||||
, mSkipAnim(false)
|
, mSkipAnim(false)
|
||||||
, mSecondsOfSwimming(0)
|
, mSecondsOfSwimming(0)
|
||||||
|
@ -905,19 +807,20 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
|
||||||
|
|
||||||
if (cls.hasInventoryStore(mPtr))
|
if (cls.hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
getActiveWeapon(cls.getCreatureStats(mPtr), cls.getInventoryStore(mPtr), &mWeaponType);
|
getActiveWeapon(mPtr, &mWeaponType);
|
||||||
if (mWeaponType != WeapType_None)
|
if (mWeaponType != ESM::Weapon::None)
|
||||||
{
|
{
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
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);
|
mAnimation->showWeapons(true);
|
||||||
// Note: controllers for ranged weapon should use time for beginning of animation to play shooting properly,
|
// 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)
|
// 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);
|
mAnimation->setWeaponGroup(mCurrentWeapon, useRelativeDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1157,11 +1060,11 @@ bool CharacterController::updateCreatureState()
|
||||||
const MWWorld::Class &cls = mPtr.getClass();
|
const MWWorld::Class &cls = mPtr.getClass();
|
||||||
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
||||||
|
|
||||||
WeaponType weapType = WeapType_None;
|
int weapType = ESM::Weapon::None;
|
||||||
if(stats.getDrawState() == DrawState_Weapon)
|
if(stats.getDrawState() == DrawState_Weapon)
|
||||||
weapType = WeapType_HandToHand;
|
weapType = ESM::Weapon::HandToHand;
|
||||||
else if (stats.getDrawState() == DrawState_Spell)
|
else if (stats.getDrawState() == DrawState_Spell)
|
||||||
weapType = WeapType_Spell;
|
weapType = ESM::Weapon::Spell;
|
||||||
|
|
||||||
if (weapType != mWeaponType)
|
if (weapType != mWeaponType)
|
||||||
{
|
{
|
||||||
|
@ -1178,7 +1081,7 @@ bool CharacterController::updateCreatureState()
|
||||||
|
|
||||||
std::string startKey = "start";
|
std::string startKey = "start";
|
||||||
std::string stopKey = "stop";
|
std::string stopKey = "stop";
|
||||||
if (weapType == WeapType_Spell)
|
if (weapType == ESM::Weapon::Spell)
|
||||||
{
|
{
|
||||||
const std::string spellid = stats.getSpells().getSelectedSpell();
|
const std::string spellid = stats.getSpells().getSelectedSpell();
|
||||||
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
|
bool canCast = mCastingManualSpell || MWBase::Environment::get().getWorld()->startSpellCast(mPtr);
|
||||||
|
@ -1214,7 +1117,7 @@ bool CharacterController::updateCreatureState()
|
||||||
mCurrentWeapon = "";
|
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();
|
mCurrentWeapon = chooseRandomAttackAnimation();
|
||||||
}
|
}
|
||||||
|
@ -1229,7 +1132,7 @@ bool CharacterController::updateCreatureState()
|
||||||
|
|
||||||
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
mAttackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
||||||
|
|
||||||
if (weapType == WeapType_HandToHand)
|
if (weapType == ESM::Weapon::HandToHand)
|
||||||
playSwishSound(0.0f);
|
playSwishSound(0.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1243,34 +1146,23 @@ bool CharacterController::updateCreatureState()
|
||||||
return false;
|
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
|
// 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",
|
// 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.
|
// but they are also present in weapon drawing animation.
|
||||||
switch (weaptype)
|
return !(getWeaponType(weaptype)->mFlags & ESM::WeaponType::TwoHanded);
|
||||||
{
|
|
||||||
case WeapType_Spell:
|
|
||||||
case WeapType_BowAndArrow:
|
|
||||||
case WeapType_Crossbow:
|
|
||||||
case WeapType_HandToHand:
|
|
||||||
case WeapType_TwoHand:
|
|
||||||
case WeapType_TwoWide:
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CharacterController::updateWeaponState(CharacterState& idle)
|
bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
{
|
{
|
||||||
const MWWorld::Class &cls = mPtr.getClass();
|
const MWWorld::Class &cls = mPtr.getClass();
|
||||||
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
CreatureStats &stats = cls.getCreatureStats(mPtr);
|
||||||
WeaponType weaptype = WeapType_None;
|
int weaptype = ESM::Weapon::None;
|
||||||
if(stats.getDrawState() == DrawState_Weapon)
|
if(stats.getDrawState() == DrawState_Weapon)
|
||||||
weaptype = WeapType_HandToHand;
|
weaptype = ESM::Weapon::HandToHand;
|
||||||
else if (stats.getDrawState() == DrawState_Spell)
|
else if (stats.getDrawState() == DrawState_Spell)
|
||||||
weaptype = WeapType_Spell;
|
weaptype = ESM::Weapon::Spell;
|
||||||
|
|
||||||
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
|
const bool isWerewolf = cls.isNpc() && cls.getNpcStats(mPtr).isWerewolf();
|
||||||
|
|
||||||
|
@ -1280,18 +1172,18 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if (mPtr.getClass().hasInventoryStore(mPtr))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(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)
|
if(stats.getDrawState() == DrawState_Spell)
|
||||||
weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
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);
|
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);
|
downSoundId = weapon->getClass().getDownSoundId(*weapon);
|
||||||
|
|
||||||
// weapon->HtH switch: weapon is empty already, so we need to take sound from previous 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);
|
downSoundId = mWeapon.getClass().getDownSoundId(mWeapon);
|
||||||
|
|
||||||
MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
MWWorld::Ptr newWeapon = weapon != inv.end() ? *weapon : MWWorld::Ptr();
|
||||||
|
@ -1312,8 +1204,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
bool forcestateupdate = false;
|
bool forcestateupdate = false;
|
||||||
|
|
||||||
// We should not play equipping animation and sound during weapon->weapon transition
|
// We should not play equipping animation and sound during weapon->weapon transition
|
||||||
bool isStillWeapon = weaptype > WeapType_HandToHand && weaptype < WeapType_Spell &&
|
bool isStillWeapon = weaptype != ESM::Weapon::HandToHand && weaptype != ESM::Weapon::Spell && weaptype != ESM::Weapon::None &&
|
||||||
mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell;
|
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),
|
// 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.
|
// 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())
|
if(!isKnockedOut() && !isKnockedDown() && !isRecovery())
|
||||||
{
|
{
|
||||||
std::string weapgroup;
|
std::string weapgroup;
|
||||||
if ((!isWerewolf || mWeaponType != WeapType_Spell)
|
if ((!isWerewolf || mWeaponType != ESM::Weapon::Spell)
|
||||||
&& weaptype != mWeaponType
|
&& weaptype != mWeaponType
|
||||||
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
&& mUpperBodyState != UpperCharState_UnEquipingWeap
|
||||||
&& !isStillWeapon)
|
&& !isStillWeapon)
|
||||||
|
@ -1340,7 +1232,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if (!weaponChanged)
|
if (!weaponChanged)
|
||||||
{
|
{
|
||||||
// Note: we do not disable unequipping animation automatically to avoid body desync
|
// Note: we do not disable unequipping animation automatically to avoid body desync
|
||||||
getWeaponGroup(mWeaponType, weapgroup);
|
weapgroup = getWeaponType(mWeaponType)->mLongGroup;
|
||||||
mAnimation->play(weapgroup, priorityWeapon,
|
mAnimation->play(weapgroup, priorityWeapon,
|
||||||
MWRender::Animation::BlendMask_All, false,
|
MWRender::Animation::BlendMask_All, false,
|
||||||
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
1.0f, "unequip start", "unequip stop", 0.0f, 0);
|
||||||
|
@ -1369,16 +1261,17 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
forcestateupdate = true;
|
forcestateupdate = true;
|
||||||
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
|
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,
|
// 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)
|
// 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);
|
mAnimation->setWeaponGroup(weapgroup, useRelativeDuration);
|
||||||
|
|
||||||
if (!isStillWeapon)
|
if (!isStillWeapon)
|
||||||
{
|
{
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
if (weaptype != WeapType_None)
|
if (weaptype != ESM::Weapon::None)
|
||||||
{
|
{
|
||||||
mAnimation->showWeapons(false);
|
mAnimation->showWeapons(false);
|
||||||
mAnimation->play(weapgroup, priorityWeapon,
|
mAnimation->play(weapgroup, priorityWeapon,
|
||||||
|
@ -1387,7 +1280,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
mUpperBodyState = UpperCharState_EquipingWeap;
|
mUpperBodyState = UpperCharState_EquipingWeap;
|
||||||
|
|
||||||
// If we do not have the "equip attach" key, show weapon manually.
|
// 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)
|
if (mAnimation->getTextKeyTime(weapgroup+": equip attach") < 0)
|
||||||
mAnimation->showWeapons(true);
|
mAnimation->showWeapons(true);
|
||||||
|
@ -1407,7 +1300,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
}
|
}
|
||||||
|
|
||||||
mWeaponType = weaptype;
|
mWeaponType = weaptype;
|
||||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
mCurrentWeapon = getWeaponType(mWeaponType)->mLongGroup;
|
||||||
|
|
||||||
if(!upSoundId.empty() && !isStillWeapon)
|
if(!upSoundId.empty() && !isStillWeapon)
|
||||||
{
|
{
|
||||||
|
@ -1421,8 +1314,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
{
|
{
|
||||||
mUpperBodyState = UpperCharState_Nothing;
|
mUpperBodyState = UpperCharState_Nothing;
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
mWeaponType = WeapType_None;
|
mWeaponType = ESM::Weapon::None;
|
||||||
getWeaponGroup(mWeaponType, mCurrentWeapon);
|
mCurrentWeapon = getWeaponType(mWeaponType)->mLongGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1433,7 +1326,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if(cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run)
|
if(cls.getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run)
|
||||||
&& mHasMovedInXY
|
&& mHasMovedInXY
|
||||||
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr)
|
&& !MWBase::Environment::get().getWorld()->isSwimming(mPtr)
|
||||||
&& mWeaponType == WeapType_None)
|
&& mWeaponType == ESM::Weapon::None)
|
||||||
{
|
{
|
||||||
if(!sndMgr->getSoundPlaying(mPtr, "WolfRun"))
|
if(!sndMgr->getSoundPlaying(mPtr, "WolfRun"))
|
||||||
sndMgr->playSound3D(mPtr, "WolfRun", 1.0f, 1.0f, MWSound::Type::Sfx,
|
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))
|
if (mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
{
|
{
|
||||||
MWWorld::InventoryStore &inv = cls.getInventoryStore(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());
|
isWeapon = (weapon != inv.end() && weapon->getTypeName() == typeid(ESM::Weapon).name());
|
||||||
if (isWeapon)
|
if (isWeapon)
|
||||||
|
{
|
||||||
weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
|
weapSpeed = weapon->get<ESM::Weapon>()->mBase->mData.mSpeed;
|
||||||
|
|
||||||
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
MWWorld::ConstContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
if (mWeaponType == WeapType_Crossbow)
|
int ammotype = getWeaponType(weapon->get<ESM::Weapon>()->mBase->mData.mType)->mAmmoType;
|
||||||
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Bolt);
|
if (ammotype != ESM::Weapon::None && (ammo == inv.end() || ammo->get<ESM::Weapon>()->mBase->mData.mType != ammotype))
|
||||||
else if (mWeaponType == WeapType_BowAndArrow)
|
ammunition = false;
|
||||||
ammunition = (ammo != inv.end() && ammo->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::Arrow);
|
}
|
||||||
|
|
||||||
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
|
if (!ammunition && mUpperBodyState > UpperCharState_WeapEquiped)
|
||||||
{
|
{
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
@ -1473,6 +1367,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
|
|
||||||
float complete;
|
float complete;
|
||||||
bool animPlaying;
|
bool animPlaying;
|
||||||
|
ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass;
|
||||||
if(mAttackingOrSpell)
|
if(mAttackingOrSpell)
|
||||||
{
|
{
|
||||||
MWWorld::Ptr player = getPlayer();
|
MWWorld::Ptr player = getPlayer();
|
||||||
|
@ -1491,7 +1386,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
mCurrentWeapon = chooseRandomAttackAnimation();
|
mCurrentWeapon = chooseRandomAttackAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mWeaponType == WeapType_Spell)
|
if(mWeaponType == ESM::Weapon::Spell)
|
||||||
{
|
{
|
||||||
// Unset casting flag, otherwise pressing the mouse button down would
|
// Unset casting flag, otherwise pressing the mouse button down would
|
||||||
// continue casting every frame if there is no animation
|
// continue casting every frame if there is no animation
|
||||||
|
@ -1597,7 +1492,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
resetIdle = false;
|
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::ContainerStoreIterator weapon = mPtr.getClass().getInventoryStore(mPtr).getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
MWWorld::Ptr item = *weapon;
|
MWWorld::Ptr item = *weapon;
|
||||||
|
@ -1627,7 +1522,8 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
{
|
{
|
||||||
std::string startKey;
|
std::string startKey;
|
||||||
std::string stopKey;
|
std::string stopKey;
|
||||||
if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_Thrown)
|
|
||||||
|
if(weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
|
||||||
{
|
{
|
||||||
mAttackType = "shoot";
|
mAttackType = "shoot";
|
||||||
startKey = mAttackType+" start";
|
startKey = mAttackType+" start";
|
||||||
|
@ -1699,7 +1595,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
attackStrength = std::min(1.f, 0.1f + Misc::Rng::rollClosedProbability());
|
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();
|
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
|
||||||
|
|
||||||
|
@ -1731,7 +1627,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if (mUpperBodyState > UpperCharState_WeapEquiped)
|
if (mUpperBodyState > UpperCharState_WeapEquiped)
|
||||||
{
|
{
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
if (mWeaponType > WeapType_HandToHand && mWeaponType < WeapType_Spell)
|
if (mWeaponType > ESM::Weapon::None)
|
||||||
mAnimation->showWeapons(true);
|
mAnimation->showWeapons(true);
|
||||||
}
|
}
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
@ -1739,9 +1635,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->setPitchFactor(0.f);
|
mAnimation->setPitchFactor(0.f);
|
||||||
if (mWeaponType == WeapType_BowAndArrow ||
|
if (weapclass == ESM::WeaponType::Ranged || weapclass == ESM::WeaponType::Thrown)
|
||||||
mWeaponType == WeapType_Thrown ||
|
|
||||||
mWeaponType == WeapType_Crossbow)
|
|
||||||
{
|
{
|
||||||
switch (mUpperBodyState)
|
switch (mUpperBodyState)
|
||||||
{
|
{
|
||||||
|
@ -1758,7 +1652,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
{
|
{
|
||||||
// technically we do not need a pitch for crossbow reload animation,
|
// technically we do not need a pitch for crossbow reload animation,
|
||||||
// but we should avoid abrupt repositioning
|
// 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));
|
mAnimation->setPitchFactor(std::max(0.f, 1.f-complete*10.f));
|
||||||
else
|
else
|
||||||
mAnimation->setPitchFactor(1.f-complete);
|
mAnimation->setPitchFactor(1.f-complete);
|
||||||
|
@ -1775,7 +1669,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
mUpperBodyState == UpperCharState_FollowStartToFollowStop ||
|
||||||
mUpperBodyState == UpperCharState_CastingSpell)
|
mUpperBodyState == UpperCharState_CastingSpell)
|
||||||
{
|
{
|
||||||
if (ammunition && mWeaponType == WeapType_Crossbow)
|
if (ammunition && mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||||
mAnimation->attachArrow();
|
mAnimation->attachArrow();
|
||||||
|
|
||||||
mUpperBodyState = UpperCharState_WeapEquiped;
|
mUpperBodyState = UpperCharState_WeapEquiped;
|
||||||
|
@ -1852,7 +1746,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
|
||||||
if(!start.empty())
|
if(!start.empty())
|
||||||
{
|
{
|
||||||
int mask = MWRender::Animation::BlendMask_All;
|
int mask = MWRender::Animation::BlendMask_All;
|
||||||
if (mWeaponType == WeapType_Crossbow)
|
if (mWeaponType == ESM::Weapon::MarksmanCrossbow)
|
||||||
mask = MWRender::Animation::BlendMask_UpperBody;
|
mask = MWRender::Animation::BlendMask_UpperBody;
|
||||||
|
|
||||||
mAnimation->disable(mCurrentWeapon);
|
mAnimation->disable(mCurrentWeapon);
|
||||||
|
@ -2639,7 +2533,7 @@ void CharacterController::resurrect()
|
||||||
mAnimation->disable(mCurrentDeath);
|
mAnimation->disable(mCurrentDeath);
|
||||||
mCurrentDeath.clear();
|
mCurrentDeath.clear();
|
||||||
mDeathState = CharState_None;
|
mDeathState = CharState_None;
|
||||||
mWeaponType = WeapType_None;
|
mWeaponType = ESM::Weapon::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::updateContinuousVfx()
|
void CharacterController::updateContinuousVfx()
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
|
|
||||||
|
#include "weapontype.hpp"
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
class InventoryStore;
|
class InventoryStore;
|
||||||
|
@ -113,21 +115,6 @@ enum CharacterState {
|
||||||
CharState_Block
|
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 {
|
enum UpperBodyCharacterState {
|
||||||
UpperCharState_Nothing,
|
UpperCharState_Nothing,
|
||||||
UpperCharState_EquipingWeap,
|
UpperCharState_EquipingWeap,
|
||||||
|
@ -186,7 +173,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
JumpingState mJumpState;
|
JumpingState mJumpState;
|
||||||
std::string mCurrentJump;
|
std::string mCurrentJump;
|
||||||
|
|
||||||
WeaponType mWeaponType;
|
int mWeaponType;
|
||||||
std::string mCurrentWeapon;
|
std::string mCurrentWeapon;
|
||||||
|
|
||||||
float mAttackStrength;
|
float mAttackStrength;
|
||||||
|
@ -212,9 +199,9 @@ class CharacterController : public MWRender::Animation::TextKeyListener
|
||||||
|
|
||||||
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
|
void refreshCurrentAnims(CharacterState idle, CharacterState movement, JumpingState jump, bool force=false);
|
||||||
void refreshHitRecoilAnims(CharacterState& idle);
|
void refreshHitRecoilAnims(CharacterState& idle);
|
||||||
void refreshJumpAnims(const WeaponInfo* weap, JumpingState jump, CharacterState& idle, bool force=false);
|
void refreshJumpAnims(const std::string& weapShortGroup, JumpingState jump, CharacterState& idle, bool force=false);
|
||||||
void refreshMovementAnims(const WeaponInfo* weap, CharacterState movement, CharacterState& idle, bool force=false);
|
void refreshMovementAnims(const std::string& weapShortGroup, CharacterState movement, CharacterState& idle, bool force=false);
|
||||||
void refreshIdleAnims(const WeaponInfo* weap, CharacterState idle, bool force=false);
|
void refreshIdleAnims(const std::string& weapShortGroup, CharacterState idle, bool force=false);
|
||||||
|
|
||||||
void clearAnimQueue(bool clearPersistAnims = 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
|
/// @param num if non-nullptr, the chosen animation number will be written here
|
||||||
std::string chooseRandomGroup (const std::string& prefix, int* num = nullptr) const;
|
std::string chooseRandomGroup (const std::string& prefix, int* num = nullptr) const;
|
||||||
|
|
||||||
bool updateCarriedLeftVisible(WeaponType weaptype) const;
|
bool updateCarriedLeftVisible(int weaptype) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
|
||||||
|
@ -312,8 +299,6 @@ public:
|
||||||
|
|
||||||
void playSwishSound(float attackStrength);
|
void playSwishSound(float attackStrength);
|
||||||
};
|
};
|
||||||
|
|
||||||
MWWorld::ContainerStoreIterator getActiveWeapon(CreatureStats &stats, MWWorld::InventoryStore &inv, WeaponType *weaptype);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* GAME_MWMECHANICS_CHARACTER_HPP */
|
#endif /* GAME_MWMECHANICS_CHARACTER_HPP */
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "npcstats.hpp"
|
#include "npcstats.hpp"
|
||||||
#include "actorutil.hpp"
|
#include "actorutil.hpp"
|
||||||
#include "aifollow.hpp"
|
#include "aifollow.hpp"
|
||||||
|
#include "weapontype.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -826,8 +827,9 @@ namespace MWMechanics
|
||||||
bool isProjectile = false;
|
bool isProjectile = false;
|
||||||
if (item.getTypeName() == typeid(ESM::Weapon).name())
|
if (item.getTypeName() == typeid(ESM::Weapon).name())
|
||||||
{
|
{
|
||||||
const ESM::Weapon* ref = item.get<ESM::Weapon>()->mBase;
|
int type = item.get<ESM::Weapon>()->mBase->mData.mType;
|
||||||
isProjectile = ref->mData.mType >= ESM::Weapon::MarksmanThrown;
|
ESM::WeaponType::Class weapclass = MWMechanics::getWeaponType(type)->mWeaponClass;
|
||||||
|
isProjectile = (weapclass == ESM::WeaponType::Thrown || weapclass == ESM::WeaponType::Ranged);
|
||||||
}
|
}
|
||||||
int type = enchantment->mData.mType;
|
int type = enchantment->mData.mType;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
#include "creaturestats.hpp"
|
#include "creaturestats.hpp"
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
|
#include "weapontype.hpp"
|
||||||
|
#include "combat.hpp"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -379,7 +381,7 @@ namespace MWMechanics
|
||||||
|
|
||||||
case ESM::MagicEffect::BoundLongbow:
|
case ESM::MagicEffect::BoundLongbow:
|
||||||
// AI should not summon the bow if there is no suitable ammo.
|
// 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;
|
return 0.f;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "aicombataction.hpp"
|
#include "aicombataction.hpp"
|
||||||
#include "spellpriority.hpp"
|
#include "spellpriority.hpp"
|
||||||
#include "spellcasting.hpp"
|
#include "spellcasting.hpp"
|
||||||
|
#include "weapontype.hpp"
|
||||||
|
|
||||||
namespace MWMechanics
|
namespace MWMechanics
|
||||||
{
|
{
|
||||||
|
@ -34,14 +35,15 @@ namespace MWMechanics
|
||||||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||||
const MWWorld::Store<ESM::GameSetting>& gmst = world->getStore().get<ESM::GameSetting>();
|
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;
|
return 0.f;
|
||||||
|
|
||||||
float rating=0.f;
|
float rating=0.f;
|
||||||
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat();
|
static const float fAIMeleeWeaponMult = gmst.find("fAIMeleeWeaponMult")->mValue.getFloat();
|
||||||
float ratingMult = fAIMeleeWeaponMult;
|
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
|
// Underwater ranged combat is impossible
|
||||||
if (world->isUnderwater(MWWorld::ConstPtr(actor), 0.75f)
|
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;
|
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
|
// 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
|
// 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;
|
rating = chop * 2;
|
||||||
}
|
}
|
||||||
else if (weapon->mData.mType >= ESM::Weapon::MarksmanBow)
|
else if (weapclass != ESM::WeaponType::Melee)
|
||||||
{
|
{
|
||||||
rating = chop;
|
rating = chop;
|
||||||
}
|
}
|
||||||
|
@ -76,25 +78,29 @@ namespace MWMechanics
|
||||||
|
|
||||||
adjustWeaponDamage(rating, item, actor);
|
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);
|
resistNormalWeapon(enemy, actor, item, rating);
|
||||||
applyWerewolfDamageMult(enemy, item, rating);
|
applyWerewolfDamageMult(enemy, item, rating);
|
||||||
}
|
}
|
||||||
else if (weapon->mData.mType == ESM::Weapon::MarksmanBow)
|
else
|
||||||
|
{
|
||||||
|
int ammotype = MWMechanics::getWeaponType(weapon->mData.mType)->mAmmoType;
|
||||||
|
if (ammotype == ESM::Weapon::Arrow)
|
||||||
{
|
{
|
||||||
if (arrowRating <= 0.f)
|
if (arrowRating <= 0.f)
|
||||||
rating = 0.f;
|
rating = 0.f;
|
||||||
else
|
else
|
||||||
rating += arrowRating;
|
rating += arrowRating;
|
||||||
}
|
}
|
||||||
else if (weapon->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
else if (ammotype == ESM::Weapon::Bolt)
|
||||||
{
|
{
|
||||||
if (boltRating <= 0.f)
|
if (boltRating <= 0.f)
|
||||||
rating = 0.f;
|
rating = 0.f;
|
||||||
else
|
else
|
||||||
rating += boltRating;
|
rating += boltRating;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!weapon->mEnchant.empty())
|
if (!weapon->mEnchant.empty())
|
||||||
{
|
{
|
||||||
|
@ -104,7 +110,7 @@ namespace MWMechanics
|
||||||
int castCost = getEffectiveEnchantmentCastCost(static_cast<float>(enchantment->mData.mCost), actor);
|
int castCost = getEffectiveEnchantmentCastCost(static_cast<float>(enchantment->mData.mCost), actor);
|
||||||
float charge = item.getCellRef().getEnchantmentCharge();
|
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);
|
rating += rateEffects(enchantment->mEffects, actor, enemy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,13 +132,13 @@ namespace MWMechanics
|
||||||
float chance = getHitChance(actor, enemy, value) / 100.f;
|
float chance = getHitChance(actor, enemy, value) / 100.f;
|
||||||
rating *= std::min(1.f, std::max(0.01f, chance));
|
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;
|
rating *= weapon->mData.mSpeed;
|
||||||
|
|
||||||
return rating * ratingMult;
|
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;
|
float bestAmmoRating = 0.f;
|
||||||
if (!actor.getClass().hasInventoryStore(actor))
|
if (!actor.getClass().hasInventoryStore(actor))
|
||||||
|
@ -153,7 +159,7 @@ namespace MWMechanics
|
||||||
return bestAmmoRating;
|
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;
|
MWWorld::Ptr emptyPtr;
|
||||||
return rateAmmo(actor, enemy, emptyPtr, ammoType);
|
return rateAmmo(actor, enemy, emptyPtr, ammoType);
|
||||||
|
@ -175,8 +181,8 @@ namespace MWMechanics
|
||||||
float bonusDamage = 0.f;
|
float bonusDamage = 0.f;
|
||||||
|
|
||||||
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
|
const ESM::Weapon* esmWeap = weapon.get<ESM::Weapon>()->mBase;
|
||||||
|
int type = esmWeap->mData.mType;
|
||||||
if (esmWeap->mData.mType >= ESM::Weapon::MarksmanBow)
|
if (getWeaponType(type)->mWeaponClass != ESM::WeaponType::Melee)
|
||||||
{
|
{
|
||||||
if (!ammo.isEmpty() && !MWBase::Environment::get().getWorld()->isSwimming(enemy))
|
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,
|
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);
|
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, MWWorld::Ptr &bestAmmo, int 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, int ammoType);
|
||||||
|
|
||||||
float vanillaRateWeaponAndAmmo(const MWWorld::Ptr& weapon, const MWWorld::Ptr& ammo, const MWWorld::Ptr& actor, const MWWorld::Ptr& enemy);
|
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/class.hpp"
|
||||||
#include "../mwworld/cellstore.hpp"
|
#include "../mwworld/cellstore.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "vismask.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
|
// Make sure we cleaned object from effects, just in cast if we re-use node
|
||||||
removeEffects();
|
removeEffects();
|
||||||
|
|
||||||
mWeaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorAnimation::~ActorAnimation()
|
ActorAnimation::~ActorAnimation()
|
||||||
|
@ -84,7 +83,7 @@ PartHolderPtr ActorAnimation::getWeaponPart(const std::string& model, const std:
|
||||||
return PartHolderPtr(new PartHolder(instance));
|
return PartHolderPtr(new PartHolder(instance));
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::Group* ActorAnimation::getBoneByName(std::string boneName)
|
osg::Group* ActorAnimation::getBoneByName(const std::string& boneName)
|
||||||
{
|
{
|
||||||
if (!mObjectRoot)
|
if (!mObjectRoot)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -105,93 +104,13 @@ std::string ActorAnimation::getHolsteredWeaponBoneName(const MWWorld::ConstPtr&
|
||||||
if(type == typeid(ESM::Weapon).name())
|
if(type == typeid(ESM::Weapon).name())
|
||||||
{
|
{
|
||||||
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon.get<ESM::Weapon>();
|
const MWWorld::LiveCellRef<ESM::Weapon> *ref = weapon.get<ESM::Weapon>();
|
||||||
ESM::Weapon::Type weaponType = (ESM::Weapon::Type)ref->mBase->mData.mType;
|
int weaponType = ref->mBase->mData.mType;
|
||||||
return getHolsteredWeaponBoneName(weaponType);
|
return MWMechanics::getWeaponType(weaponType)->mSheathingBone;
|
||||||
}
|
}
|
||||||
|
|
||||||
return boneName;
|
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)
|
void ActorAnimation::resetControllers(osg::Node* node)
|
||||||
{
|
{
|
||||||
if (node == nullptr)
|
if (node == nullptr)
|
||||||
|
@ -205,7 +124,8 @@ void ActorAnimation::resetControllers(osg::Node* node)
|
||||||
|
|
||||||
void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||||
{
|
{
|
||||||
if (!mWeaponSheathing)
|
static const bool weaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
||||||
|
if (!weaponSheathing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
|
@ -219,7 +139,8 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Since throwing weapons stack themselves, do not show such weapon itself
|
// 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;
|
showHolsteredWeapons = false;
|
||||||
|
|
||||||
std::string mesh = weapon->getClass().getModel(*weapon);
|
std::string mesh = weapon->getClass().getModel(*weapon);
|
||||||
|
@ -279,7 +200,8 @@ void ActorAnimation::updateHolsteredWeapon(bool showHolsteredWeapons)
|
||||||
|
|
||||||
void ActorAnimation::updateQuiver()
|
void ActorAnimation::updateQuiver()
|
||||||
{
|
{
|
||||||
if (!mWeaponSheathing)
|
static const bool weaponSheathing = Settings::Manager::getBool("weapon sheathing", "Game");
|
||||||
|
if (!weaponSheathing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
if (!mPtr.getClass().hasInventoryStore(mPtr))
|
||||||
|
@ -303,10 +225,12 @@ void ActorAnimation::updateQuiver()
|
||||||
bool suitableAmmo = false;
|
bool suitableAmmo = false;
|
||||||
MWWorld::ConstContainerStoreIterator ammo = weapon;
|
MWWorld::ConstContainerStoreIterator ammo = weapon;
|
||||||
unsigned int ammoCount = 0;
|
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();
|
ammoCount = ammo->getRefData().getCount();
|
||||||
osg::Group* throwingWeaponNode = getBoneByName("Weapon Bone");
|
osg::Group* throwingWeaponNode = getBoneByName(weaponType->mAttachBone);
|
||||||
if (throwingWeaponNode && throwingWeaponNode->getNumChildren())
|
if (throwingWeaponNode && throwingWeaponNode->getNumChildren())
|
||||||
ammoCount--;
|
ammoCount--;
|
||||||
|
|
||||||
|
@ -323,10 +247,7 @@ void ActorAnimation::updateQuiver()
|
||||||
if (arrowAttached)
|
if (arrowAttached)
|
||||||
ammoCount--;
|
ammoCount--;
|
||||||
|
|
||||||
if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
suitableAmmo = ammo->get<ESM::Weapon>()->mBase->mData.mType == weaponType->mAmmoType;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!suitableAmmo)
|
if (!suitableAmmo)
|
||||||
|
@ -382,7 +303,8 @@ void ActorAnimation::itemAdded(const MWWorld::ConstPtr& item, int /*count*/)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MWWorld::ConstContainerStoreIterator ammo = inv.end();
|
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;
|
ammo = weapon;
|
||||||
else
|
else
|
||||||
ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
@ -415,7 +337,8 @@ void ActorAnimation::itemRemoved(const MWWorld::ConstPtr& item, int /*count*/)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MWWorld::ConstContainerStoreIterator ammo = inv.end();
|
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;
|
ammo = weapon;
|
||||||
else
|
else
|
||||||
ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
|
||||||
|
|
|
@ -40,13 +40,10 @@ class ActorAnimation : public Animation, public MWWorld::ContainerStoreListener
|
||||||
virtual bool isArrowAttached() const { return false; }
|
virtual bool isArrowAttached() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool mWeaponSheathing;
|
osg::Group* getBoneByName(const std::string& boneName);
|
||||||
osg::Group* getBoneByName(std::string boneName);
|
|
||||||
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
virtual void updateHolsteredWeapon(bool showHolsteredWeapons);
|
||||||
virtual void injectWeaponBones();
|
|
||||||
virtual void updateQuiver();
|
virtual void updateQuiver();
|
||||||
virtual std::string getHolsteredWeaponBoneName(const MWWorld::ConstPtr& weapon);
|
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, bool enchantedGlow, osg::Vec4f* glowColor);
|
||||||
virtual PartHolderPtr getWeaponPart(const std::string& model, const std::string& bonename)
|
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;
|
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
|
class RemoveFinishedCallbackVisitor : public RemoveVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -1336,8 +1355,66 @@ namespace MWRender
|
||||||
state->second.mLoopingEnabled = enabled;
|
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)
|
if (baseonly)
|
||||||
{
|
{
|
||||||
typedef std::map<std::string, osg::ref_ptr<osg::Node> > Cache;
|
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);
|
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;
|
SceneUtil::CleanObjectRootVisitor removeDrawableVisitor;
|
||||||
created->accept(removeDrawableVisitor);
|
created->accept(removeDrawableVisitor);
|
||||||
removeDrawableVisitor.remove();
|
removeDrawableVisitor.remove();
|
||||||
|
@ -1359,7 +1442,17 @@ namespace MWRender
|
||||||
return sceneMgr->createInstance(found->second);
|
return sceneMgr->createInstance(found->second);
|
||||||
}
|
}
|
||||||
else
|
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)
|
void Animation::setObjectRoot(const std::string &model, bool forceskeleton, bool baseonly, bool isCreature)
|
||||||
|
@ -1381,9 +1474,18 @@ namespace MWRender
|
||||||
mAccumRoot = nullptr;
|
mAccumRoot = nullptr;
|
||||||
mAccumCtrl = 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)
|
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);
|
mInsert->addChild(created);
|
||||||
mObjectRoot = created->asGroup();
|
mObjectRoot = created->asGroup();
|
||||||
if (!mObjectRoot)
|
if (!mObjectRoot)
|
||||||
|
@ -1399,7 +1501,7 @@ namespace MWRender
|
||||||
}
|
}
|
||||||
else
|
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());
|
osg::ref_ptr<SceneUtil::Skeleton> skel = dynamic_cast<SceneUtil::Skeleton*>(created.get());
|
||||||
if (!skel)
|
if (!skel)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "../mwworld/inventorystore.hpp"
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "npcanimation.hpp"
|
#include "npcanimation.hpp"
|
||||||
#include "vismask.hpp"
|
#include "vismask.hpp"
|
||||||
|
@ -290,55 +291,25 @@ namespace MWRender
|
||||||
|
|
||||||
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
|
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
|
||||||
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
|
||||||
std::string groupname;
|
std::string groupname = "inventoryhandtohand";
|
||||||
bool showCarriedLeft = true;
|
bool showCarriedLeft = true;
|
||||||
if(iter == inv.end())
|
if(iter != inv.end())
|
||||||
groupname = "inventoryhandtohand";
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
const std::string &typeName = iter->getTypeName();
|
|
||||||
if(typeName == typeid(ESM::Lockpick).name() || typeName == typeid(ESM::Probe).name())
|
|
||||||
groupname = "inventoryweapononehand";
|
groupname = "inventoryweapononehand";
|
||||||
else if(typeName == typeid(ESM::Weapon).name())
|
if(iter->getTypeName() == typeid(ESM::Weapon).name())
|
||||||
{
|
{
|
||||||
MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>();
|
MWWorld::LiveCellRef<ESM::Weapon> *ref = iter->get<ESM::Weapon>();
|
||||||
|
|
||||||
int type = ref->mBase->mData.mType;
|
int type = ref->mBase->mData.mType;
|
||||||
if(type == ESM::Weapon::ShortBladeOneHand ||
|
const ESM::WeaponType* weaponInfo = MWMechanics::getWeaponType(type);
|
||||||
type == ESM::Weapon::LongBladeOneHand ||
|
showCarriedLeft = !(weaponInfo->mFlags & ESM::WeaponType::TwoHanded);
|
||||||
type == ESM::Weapon::BluntOneHand ||
|
|
||||||
type == ESM::Weapon::AxeOneHand ||
|
std::string inventoryGroup = weaponInfo->mLongGroup;
|
||||||
type == ESM::Weapon::MarksmanThrown)
|
inventoryGroup = "inventory" + inventoryGroup;
|
||||||
{
|
|
||||||
groupname = "inventoryweapononehand";
|
// We still should use one-handed animation as fallback
|
||||||
|
if (mAnimation->hasAnimation(inventoryGroup))
|
||||||
|
groupname = inventoryGroup;
|
||||||
}
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
groupname = "inventoryhandtohand";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mAnimation->showCarriedLeft(showCarriedLeft);
|
mAnimation->showCarriedLeft(showCarriedLeft);
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
|
@ -50,9 +52,6 @@ CreatureWeaponAnimation::CreatureWeaponAnimation(const MWWorld::Ptr &ptr, const
|
||||||
|
|
||||||
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
if((ref->mBase->mFlags&ESM::Creature::Bipedal))
|
||||||
{
|
{
|
||||||
if (mWeaponSheathing)
|
|
||||||
injectWeaponBones();
|
|
||||||
|
|
||||||
addAnimSource("meshes\\xbase_anim.nif", model);
|
addAnimSource("meshes\\xbase_anim.nif", model);
|
||||||
}
|
}
|
||||||
addAnimSource(model, model);
|
addAnimSource(model, model);
|
||||||
|
@ -115,7 +114,15 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
|
||||||
|
|
||||||
std::string bonename;
|
std::string bonename;
|
||||||
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
|
if (slot == MWWorld::InventoryStore::Slot_CarriedRight)
|
||||||
|
{
|
||||||
|
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";
|
bonename = "Weapon Bone";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
bonename = "Shield Bone";
|
bonename = "Shield Bone";
|
||||||
|
|
||||||
|
@ -140,8 +147,9 @@ void CreatureWeaponAnimation::updatePart(PartHolderPtr& scene, int slot)
|
||||||
item.getTypeName() == typeid(ESM::Weapon).name() &&
|
item.getTypeName() == typeid(ESM::Weapon).name() &&
|
||||||
item.get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
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);
|
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();
|
attachArrow();
|
||||||
else
|
else
|
||||||
mAmmunition.reset();
|
mAmmunition.reset();
|
||||||
|
@ -197,7 +205,19 @@ osg::Group *CreatureWeaponAnimation::getArrowBone()
|
||||||
if (!mWeapon)
|
if (!mWeapon)
|
||||||
return nullptr;
|
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);
|
mWeapon->getNode()->accept(findVisitor);
|
||||||
|
|
||||||
return findVisitor.mFoundNode;
|
return findVisitor.mFoundNode;
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "../mwbase/environment.hpp"
|
#include "../mwbase/environment.hpp"
|
||||||
#include "../mwbase/world.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_LLeg, "Left Upper Leg"));
|
||||||
result.insert(std::make_pair(ESM::PRT_RPauldron, "Right Clavicle"));
|
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_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"));
|
result.insert(std::make_pair(ESM::PRT_Tail, "Tail"));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -318,12 +319,6 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
|
||||||
if(mViewMode == viewMode)
|
if(mViewMode == viewMode)
|
||||||
return;
|
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;
|
mViewMode = viewMode;
|
||||||
MWBase::Environment::get().getWorld()->scaleObject(mPtr, mPtr.getCellRef().getScale()); // apply race height after view change
|
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);
|
setObjectRoot(smodel, true, true, false);
|
||||||
|
|
||||||
if (mWeaponSheathing)
|
|
||||||
injectWeaponBones();
|
|
||||||
|
|
||||||
updateParts();
|
updateParts();
|
||||||
|
|
||||||
if(!is1stPerson)
|
if(!is1stPerson)
|
||||||
|
@ -745,7 +737,18 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
|
||||||
mPartPriorities[type] = priority;
|
mPartPriorities[type] = priority;
|
||||||
try
|
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
|
// 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;
|
const std::string bonefilter = (type == ESM::PRT_Hair) ? "hair" : bonename;
|
||||||
mObjectParts[type] = insertBoundedPart(mesh, bonename, bonefilter, enchantedGlow, glowColor);
|
mObjectParts[type] = insertBoundedPart(mesh, bonename, bonefilter, enchantedGlow, glowColor);
|
||||||
|
@ -906,8 +909,9 @@ void NpcAnimation::showWeapons(bool showWeapon)
|
||||||
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
if (weapon->getTypeName() == typeid(ESM::Weapon).name() &&
|
||||||
weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanCrossbow)
|
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);
|
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();
|
attachArrow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -972,7 +976,15 @@ osg::Group* NpcAnimation::getArrowBone()
|
||||||
if (!part)
|
if (!part)
|
||||||
return nullptr;
|
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);
|
part->getNode()->accept(findVisitor);
|
||||||
|
|
||||||
return findVisitor.mFoundNode;
|
return findVisitor.mFoundNode;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "../mwmechanics/creaturestats.hpp"
|
#include "../mwmechanics/creaturestats.hpp"
|
||||||
#include "../mwmechanics/combat.hpp"
|
#include "../mwmechanics/combat.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "animation.hpp"
|
#include "animation.hpp"
|
||||||
#include "rotatecontroller.hpp"
|
#include "rotatecontroller.hpp"
|
||||||
|
@ -67,8 +68,10 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
||||||
return;
|
return;
|
||||||
if (weaponSlot->getTypeName() != typeid(ESM::Weapon).name())
|
if (weaponSlot->getTypeName() != typeid(ESM::Weapon).name())
|
||||||
return;
|
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);
|
std::string soundid = weaponSlot->getClass().getUpSoundId(*weaponSlot);
|
||||||
if(!soundid.empty())
|
if(!soundid.empty())
|
||||||
|
@ -78,7 +81,7 @@ void WeaponAnimation::attachArrow(MWWorld::Ptr actor)
|
||||||
}
|
}
|
||||||
showWeapon(true);
|
showWeapon(true);
|
||||||
}
|
}
|
||||||
else if (weaponType == ESM::Weapon::MarksmanBow || weaponType == ESM::Weapon::MarksmanCrossbow)
|
else if (weapclass == ESM::WeaponType::Ranged)
|
||||||
{
|
{
|
||||||
osg::Group* parent = getArrowBone();
|
osg::Group* parent = getArrowBone();
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
@ -113,7 +116,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength)
|
||||||
|
|
||||||
MWMechanics::applyFatigueLoss(actor, *weapon, 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
|
// Thrown weapons get detached now
|
||||||
osg::Node* weaponNode = getWeaponNode();
|
osg::Node* weaponNode = getWeaponNode();
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "../mwmechanics/npcstats.hpp"
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "esmstore.hpp"
|
#include "esmstore.hpp"
|
||||||
#include "class.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;
|
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;
|
continue;
|
||||||
|
|
||||||
if (iter->getClass().getEquipmentSkill(*iter) == weaponSkills[maxWeaponSkill])
|
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)
|
if (weapon != end() && weapon->getClass().canBeEquipped(*weapon, actor).first)
|
||||||
{
|
{
|
||||||
// Do not equip ranged weapons, if there is no suitable ammo
|
// Do not equip ranged weapons, if there is no suitable ammo
|
||||||
bool hasAmmo = true;
|
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())
|
if (arrow == end())
|
||||||
hasAmmo = false;
|
hasAmmo = false;
|
||||||
else
|
else
|
||||||
slots_[Slot_Ammunition] = arrow;
|
slots_[Slot_Ammunition] = arrow;
|
||||||
}
|
}
|
||||||
if (isCrossbow == true)
|
else if (ammotype == ESM::Weapon::Bolt)
|
||||||
{
|
{
|
||||||
if (bolt == end())
|
if (bolt == end())
|
||||||
hasAmmo = false;
|
hasAmmo = false;
|
||||||
|
@ -406,7 +396,7 @@ void MWWorld::InventoryStore::autoEquipWeapon (const MWWorld::Ptr& actor, TSlots
|
||||||
int slot = itemsSlots.first.front();
|
int slot = itemsSlots.first.front();
|
||||||
slots_[slot] = weapon;
|
slots_[slot] = weapon;
|
||||||
|
|
||||||
if (!isBow && !isCrossbow)
|
if (ammotype == ESM::Weapon::None)
|
||||||
slots_[Slot_Ammunition] = end();
|
slots_[Slot_Ammunition] = end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "../mwmechanics/spellcasting.hpp"
|
#include "../mwmechanics/spellcasting.hpp"
|
||||||
#include "../mwmechanics/actorutil.hpp"
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
#include "../mwmechanics/aipackage.hpp"
|
#include "../mwmechanics/aipackage.hpp"
|
||||||
|
#include "../mwmechanics/weapontype.hpp"
|
||||||
|
|
||||||
#include "../mwrender/animation.hpp"
|
#include "../mwrender/animation.hpp"
|
||||||
#include "../mwrender/vismask.hpp"
|
#include "../mwrender/vismask.hpp"
|
||||||
|
@ -317,7 +318,9 @@ namespace MWWorld
|
||||||
state.mIdArrow = projectile.getCellRef().getRefId();
|
state.mIdArrow = projectile.getCellRef().getRefId();
|
||||||
state.mCasterHandle = actor;
|
state.mCasterHandle = actor;
|
||||||
state.mAttackStrength = attackStrength;
|
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::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), projectile.getCellRef().getRefId());
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
|
@ -604,7 +607,9 @@ namespace MWWorld
|
||||||
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
|
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), esm.mId);
|
||||||
MWWorld::Ptr ptr = ref.getPtr();
|
MWWorld::Ptr ptr = ref.getPtr();
|
||||||
model = ptr.getClass().getModel(ptr);
|
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(...)
|
catch(...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -388,6 +388,30 @@ namespace MWWorld
|
||||||
iterator end() const;
|
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
|
} //end namespace
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "loadskil.hpp"
|
||||||
|
|
||||||
namespace ESM
|
namespace ESM
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -21,6 +23,10 @@ struct Weapon
|
||||||
|
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
|
PickProbe = -4,
|
||||||
|
HandToHand = -3,
|
||||||
|
Spell = -2,
|
||||||
|
None = -1,
|
||||||
ShortBladeOneHand = 0,
|
ShortBladeOneHand = 0,
|
||||||
LongBladeOneHand = 1,
|
LongBladeOneHand = 1,
|
||||||
LongBladeTwoHand = 2,
|
LongBladeTwoHand = 2,
|
||||||
|
@ -75,5 +81,34 @@ struct Weapon
|
||||||
void blank();
|
void blank();
|
||||||
///< Set record to default state (does not touch the ID).
|
///< 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
|
#endif
|
||||||
|
|
|
@ -540,6 +540,10 @@ namespace NifOsg
|
||||||
// Marker objects. These meshes are only visible in the editor.
|
// Marker objects. These meshes are only visible in the editor.
|
||||||
hasMarkers = true;
|
hasMarkers = true;
|
||||||
}
|
}
|
||||||
|
else if(sd->string == "BONE")
|
||||||
|
{
|
||||||
|
node->getOrCreateUserDataContainer()->addDescription("CustomBone");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue