@ -2,10 +2,12 @@
# include "creature.hpp"
# include "creature.hpp"
# include <components/esm/loadcrea.hpp>
# include <components/esm/loadcrea.hpp>
# include <components/esm/creaturestate.hpp>
# include "../mwmechanics/creaturestats.hpp"
# include "../mwmechanics/creaturestats.hpp"
# include "../mwmechanics/magiceffects.hpp"
# include "../mwmechanics/magiceffects.hpp"
# include "../mwmechanics/movement.hpp"
# include "../mwmechanics/movement.hpp"
# include "../mwmechanics/spellcasting.hpp"
# include "../mwbase/environment.hpp"
# include "../mwbase/environment.hpp"
# include "../mwbase/mechanicsmanager.hpp"
# include "../mwbase/mechanicsmanager.hpp"
@ -26,22 +28,30 @@
# include "../mwgui/tooltips.hpp"
# include "../mwgui/tooltips.hpp"
# include "../mwworld/inventorystore.hpp"
# include "../mwmechanics/npcstats.hpp"
# include "../mwmechanics/npcstats.hpp"
# include "../mwmechanics/combat.hpp"
namespace
namespace
{
{
struct CustomData : public MWWorld : : CustomData
struct CustomData : public MWWorld : : CustomData
{
{
MWMechanics : : CreatureStats mCreatureStats ;
MWMechanics : : CreatureStats mCreatureStats ;
MWWorld : : ContainerStore mContainerStore ;
MWWorld : : ContainerStore * mContainerStore ; // may be InventoryStore for some creatures
MWMechanics : : Movement mMovement ;
MWMechanics : : Movement mMovement ;
virtual MWWorld : : CustomData * clone ( ) const ;
virtual MWWorld : : CustomData * clone ( ) const ;
CustomData ( ) : mContainerStore ( 0 ) { }
virtual ~ CustomData ( ) { delete mContainerStore ; }
} ;
} ;
MWWorld : : CustomData * CustomData : : clone ( ) const
MWWorld : : CustomData * CustomData : : clone ( ) const
{
{
return new CustomData ( * this ) ;
CustomData * cloned = new CustomData ( * this ) ;
cloned - > mContainerStore = mContainerStore - > clone ( ) ;
return cloned ;
}
}
}
}
@ -61,6 +71,17 @@ namespace MWClass
fMinWalkSpeedCreature = gmst . find ( " fMinWalkSpeedCreature " ) ;
fMinWalkSpeedCreature = gmst . find ( " fMinWalkSpeedCreature " ) ;
fMaxWalkSpeedCreature = gmst . find ( " fMaxWalkSpeedCreature " ) ;
fMaxWalkSpeedCreature = gmst . find ( " fMaxWalkSpeedCreature " ) ;
fEncumberedMoveEffect = gmst . find ( " fEncumberedMoveEffect " ) ;
fSneakSpeedMultiplier = gmst . find ( " fSneakSpeedMultiplier " ) ;
fAthleticsRunBonus = gmst . find ( " fAthleticsRunBonus " ) ;
fBaseRunMultiplier = gmst . find ( " fBaseRunMultiplier " ) ;
fMinFlySpeed = gmst . find ( " fMinFlySpeed " ) ;
fMaxFlySpeed = gmst . find ( " fMaxFlySpeed " ) ;
fSwimRunBase = gmst . find ( " fSwimRunBase " ) ;
fSwimRunAthleticsMult = gmst . find ( " fSwimRunAthleticsMult " ) ;
fKnockDownMult = gmst . find ( " fKnockDownMult " ) ;
iKnockDownOddsMult = gmst . find ( " iKnockDownOddsMult " ) ;
iKnockDownOddsBase = gmst . find ( " iKnockDownOddsBase " ) ;
inited = true ;
inited = true ;
}
}
@ -68,14 +89,14 @@ namespace MWClass
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
// creature stats
// creature stats
data - > mCreatureStats . getAttribute( 0 ) . set ( ref - > mBase - > mData . mStrength ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Strength , ref - > mBase - > mData . mStrength ) ;
data - > mCreatureStats . getAttribute( 1 ) . set ( ref - > mBase - > mData . mIntelligence ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Intelligence , ref - > mBase - > mData . mIntelligence ) ;
data - > mCreatureStats . getAttribute( 2 ) . set ( ref - > mBase - > mData . mWillpower ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Willpower , ref - > mBase - > mData . mWillpower ) ;
data - > mCreatureStats . getAttribute( 3 ) . set ( ref - > mBase - > mData . mAgility ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Agility , ref - > mBase - > mData . mAgility ) ;
data - > mCreatureStats . getAttribute( 4 ) . set ( ref - > mBase - > mData . mSpeed ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Speed , ref - > mBase - > mData . mSpeed ) ;
data - > mCreatureStats . getAttribute( 5 ) . set ( ref - > mBase - > mData . mEndurance ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Endurance , ref - > mBase - > mData . mEndurance ) ;
data - > mCreatureStats . getAttribute( 6 ) . set ( ref - > mBase - > mData . mPersonality ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Personality , ref - > mBase - > mData . mPersonality ) ;
data - > mCreatureStats . getAttribute( 7 ) . set ( ref - > mBase - > mData . mLuck ) ;
data - > mCreatureStats . setAttribute( ESM : : Attribute : : Luck , ref - > mBase - > mData . mLuck ) ;
data - > mCreatureStats . setHealth ( ref - > mBase - > mData . mHealth ) ;
data - > mCreatureStats . setHealth ( ref - > mBase - > mData . mHealth ) ;
data - > mCreatureStats . setMagicka ( ref - > mBase - > mData . mMana ) ;
data - > mCreatureStats . setMagicka ( ref - > mBase - > mData . mMana ) ;
data - > mCreatureStats . setFatigue ( ref - > mBase - > mData . mFatigue ) ;
data - > mCreatureStats . setFatigue ( ref - > mBase - > mData . mFatigue ) ;
@ -84,10 +105,10 @@ namespace MWClass
data - > mCreatureStats . getAiSequence ( ) . fill ( ref - > mBase - > mAiPackage ) ;
data - > mCreatureStats . getAiSequence ( ) . fill ( ref - > mBase - > mAiPackage ) ;
data - > mCreatureStats . setAiSetting ( 0 , ref - > mBase - > mAiData . mHello ) ;
data - > mCreatureStats . setAiSetting ( MWMechanics : : CreatureStats : : AI_Hello , ref - > mBase - > mAiData . mHello ) ;
data - > mCreatureStats . setAiSetting ( 1 , ref - > mBase - > mAiData . mFight ) ;
data - > mCreatureStats . setAiSetting ( MWMechanics : : CreatureStats : : AI_Fight , ref - > mBase - > mAiData . mFight ) ;
data - > mCreatureStats . setAiSetting ( 2 , ref - > mBase - > mAiData . mFlee ) ;
data - > mCreatureStats . setAiSetting ( MWMechanics : : CreatureStats : : AI_Flee , ref - > mBase - > mAiData . mFlee ) ;
data - > mCreatureStats . setAiSetting ( 3 , ref - > mBase - > mAiData . mAlarm ) ;
data - > mCreatureStats . setAiSetting ( MWMechanics : : CreatureStats : : AI_Alarm , ref - > mBase - > mAiData . mAlarm ) ;
// spells
// spells
for ( std : : vector < std : : string > : : const_iterator iter ( ref - > mBase - > mSpells . mList . begin ( ) ) ;
for ( std : : vector < std : : string > : : const_iterator iter ( ref - > mBase - > mSpells . mList . begin ( ) ) ;
@ -95,13 +116,23 @@ namespace MWClass
data - > mCreatureStats . getSpells ( ) . add ( * iter ) ;
data - > mCreatureStats . getSpells ( ) . add ( * iter ) ;
// inventory
// inventory
data - > mContainerStore . fill ( ref - > mBase - > mInventory , getId ( ptr ) ,
if ( ref - > mBase - > mFlags & ESM : : Creature : : Weapon )
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) ) ;
data - > mContainerStore = new MWWorld : : InventoryStore ( ) ;
else
data - > mContainerStore . add ( " gold_001 " , ref - > mBase - > mData . mGold , ptr ) ;
data - > mContainerStore = new MWWorld : : ContainerStore ( ) ;
// store
// store
ptr . getRefData ( ) . setCustomData ( data . release ( ) ) ;
ptr . getRefData ( ) . setCustomData ( data . release ( ) ) ;
getContainerStore ( ptr ) . fill ( ref - > mBase - > mInventory , getId ( ptr ) , " " ,
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) ) ;
// TODO: this is not quite correct, in vanilla the merchant's gold pool is not available in his inventory.
// (except for gold you gave him)
getContainerStore ( ptr ) . add ( MWWorld : : ContainerStore : : sGoldId , ref - > mBase - > mData . mGold , ptr ) ;
if ( ref - > mBase - > mFlags & ESM : : Creature : : Weapon )
getInventoryStore ( ptr ) . autoEquip ( ptr ) ;
}
}
}
}
@ -120,8 +151,10 @@ namespace MWClass
void Creature : : insertObjectRendering ( const MWWorld : : Ptr & ptr , MWRender : : RenderingInterface & renderingInterface ) const
void Creature : : insertObjectRendering ( const MWWorld : : Ptr & ptr , MWRender : : RenderingInterface & renderingInterface ) const
{
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
MWRender : : Actors & actors = renderingInterface . getActors ( ) ;
MWRender : : Actors & actors = renderingInterface . getActors ( ) ;
actors . insertCreature ( ptr ) ;
actors . insertCreature ( ptr , ref - > mBase - > mFlags & ESM : : Creature : : Weapon );
}
}
void Creature : : insertObject ( const MWWorld : : Ptr & ptr , MWWorld : : PhysicsSystem & physics ) const
void Creature : : insertObject ( const MWWorld : : Ptr & ptr , MWWorld : : PhysicsSystem & physics ) const
@ -163,6 +196,144 @@ namespace MWClass
void Creature : : hit ( const MWWorld : : Ptr & ptr , int type ) const
void Creature : : hit ( const MWWorld : : Ptr & ptr , int type ) const
{
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref =
ptr . get < ESM : : Creature > ( ) ;
const MWWorld : : Store < ESM : : GameSetting > & gmst = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : GameSetting > ( ) ;
MWMechanics : : CreatureStats & stats = getCreatureStats ( ptr ) ;
// Get the weapon used (if hand-to-hand, weapon = inv.end())
MWWorld : : Ptr weapon ;
if ( ptr . getClass ( ) . hasInventoryStore ( ptr ) )
{
MWWorld : : InventoryStore & inv = getInventoryStore ( ptr ) ;
MWWorld : : ContainerStoreIterator weaponslot = inv . getSlot ( MWWorld : : InventoryStore : : Slot_CarriedRight ) ;
if ( weaponslot ! = inv . end ( ) & & weaponslot - > getTypeName ( ) = = typeid ( ESM : : Weapon ) . name ( ) )
weapon = * weaponslot ;
}
// Reduce fatigue
// somewhat of a guess, but using the weapon weight makes sense
const float fFatigueAttackBase = gmst . find ( " fFatigueAttackBase " ) - > getFloat ( ) ;
const float fFatigueAttackMult = gmst . find ( " fFatigueAttackMult " ) - > getFloat ( ) ;
const float fWeaponFatigueMult = gmst . find ( " fWeaponFatigueMult " ) - > getFloat ( ) ;
MWMechanics : : DynamicStat < float > fatigue = stats . getFatigue ( ) ;
const float normalizedEncumbrance = getEncumbrance ( ptr ) / getCapacity ( ptr ) ;
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult ;
if ( ! weapon . isEmpty ( ) )
fatigueLoss + = weapon . getClass ( ) . getWeight ( weapon ) * stats . getAttackStrength ( ) * fWeaponFatigueMult ;
fatigue . setCurrent ( fatigue . getCurrent ( ) - fatigueLoss ) ;
stats . setFatigue ( fatigue ) ;
// TODO: where is the distance defined?
float dist = 200.f ;
if ( ! weapon . isEmpty ( ) )
{
const float fCombatDistance = gmst . find ( " fCombatDistance " ) - > getFloat ( ) ;
dist = fCombatDistance * weapon . get < ESM : : Weapon > ( ) - > mBase - > mData . mReach ;
}
std : : pair < MWWorld : : Ptr , Ogre : : Vector3 > result = MWBase : : Environment : : get ( ) . getWorld ( ) - > getHitContact ( ptr , dist ) ;
if ( result . first . isEmpty ( ) )
return ; // Didn't hit anything
MWWorld : : Ptr victim = result . first ;
if ( ! victim . getClass ( ) . isActor ( ) )
return ; // Can't hit non-actors
Ogre : : Vector3 hitPosition = result . second ;
MWMechanics : : CreatureStats & otherstats = victim . getClass ( ) . getCreatureStats ( victim ) ;
const MWMechanics : : MagicEffects & mageffects = stats . getMagicEffects ( ) ;
float hitchance = ref - > mBase - > mData . mCombat +
( stats . getAttribute ( ESM : : Attribute : : Agility ) . getModified ( ) / 5.0f ) +
( stats . getAttribute ( ESM : : Attribute : : Luck ) . getModified ( ) / 10.0f ) ;
hitchance * = stats . getFatigueTerm ( ) ;
hitchance + = mageffects . get ( ESM : : MagicEffect : : FortifyAttack ) . mMagnitude -
mageffects . get ( ESM : : MagicEffect : : Blind ) . mMagnitude ;
hitchance - = otherstats . getEvasion ( ) ;
if ( ( : : rand ( ) / ( RAND_MAX + 1.0 ) ) > hitchance / 100.0f )
{
victim . getClass ( ) . onHit ( victim , 0.0f , false , MWWorld : : Ptr ( ) , ptr , false ) ;
return ;
}
int min , max ;
switch ( type )
{
case 0 :
min = ref - > mBase - > mData . mAttack [ 0 ] ;
max = ref - > mBase - > mData . mAttack [ 1 ] ;
break ;
case 1 :
min = ref - > mBase - > mData . mAttack [ 2 ] ;
max = ref - > mBase - > mData . mAttack [ 3 ] ;
break ;
case 2 :
default :
min = ref - > mBase - > mData . mAttack [ 4 ] ;
max = ref - > mBase - > mData . mAttack [ 5 ] ;
break ;
}
// I think this should be random, since attack1-3 animations don't have an attack strength like NPCs do
float damage = min + ( max - min ) * : : rand ( ) / ( RAND_MAX + 1.0 ) ;
if ( ! weapon . isEmpty ( ) )
{
const bool weaphashealth = get ( weapon ) . hasItemHealth ( weapon ) ;
const unsigned char * attack = NULL ;
if ( type = = ESM : : Weapon : : AT_Chop )
attack = weapon . get < ESM : : Weapon > ( ) - > mBase - > mData . mChop ;
else if ( type = = ESM : : Weapon : : AT_Slash )
attack = weapon . get < ESM : : Weapon > ( ) - > mBase - > mData . mSlash ;
else if ( type = = ESM : : Weapon : : AT_Thrust )
attack = weapon . get < ESM : : Weapon > ( ) - > mBase - > mData . mThrust ;
if ( attack )
{
float weaponDamage = attack [ 0 ] + ( ( attack [ 1 ] - attack [ 0 ] ) * stats . getAttackStrength ( ) ) ;
weaponDamage * = 0.5f + ( stats . getAttribute ( ESM : : Attribute : : Luck ) . getModified ( ) / 100.0f ) ;
if ( weaphashealth )
{
int weapmaxhealth = weapon . get < ESM : : Weapon > ( ) - > mBase - > mData . mHealth ;
if ( weapon . getCellRef ( ) . mCharge = = - 1 )
weapon . getCellRef ( ) . mCharge = weapmaxhealth ;
weaponDamage * = float ( weapon . getCellRef ( ) . mCharge ) / weapmaxhealth ;
}
if ( ! MWBase : : Environment : : get ( ) . getWorld ( ) - > getGodModeState ( ) )
weapon . getCellRef ( ) . mCharge - = std : : min ( std : : max ( 1 ,
( int ) ( damage * gmst . find ( " fWeaponDamageMult " ) - > getFloat ( ) ) ) , weapon . getCellRef ( ) . mCharge ) ;
// Weapon broken? unequip it
if ( weapon . getCellRef ( ) . mCharge = = 0 )
weapon = * getInventoryStore ( ptr ) . unequipItem ( weapon , ptr ) ;
damage + = weaponDamage ;
}
// Apply "On hit" enchanted weapons
std : : string enchantmentName = ! weapon . isEmpty ( ) ? weapon . getClass ( ) . getEnchantment ( weapon ) : " " ;
if ( ! enchantmentName . empty ( ) )
{
const ESM : : Enchantment * enchantment = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Enchantment > ( ) . find (
enchantmentName ) ;
if ( enchantment - > mData . mType = = ESM : : Enchantment : : WhenStrikes )
{
MWMechanics : : CastSpell cast ( ptr , victim ) ;
cast . mHitPosition = hitPosition ;
cast . cast ( weapon ) ;
}
}
}
if ( ! weapon . isEmpty ( ) & & MWMechanics : : blockMeleeAttack ( ptr , victim , weapon , damage ) )
damage = 0 ;
if ( damage > 0 )
MWBase : : Environment : : get ( ) . getWorld ( ) - > spawnBloodEffect ( victim , hitPosition ) ;
victim . getClass ( ) . onHit ( victim , damage , true , weapon , ptr , true ) ;
}
}
void Creature : : onHit ( const MWWorld : : Ptr & ptr , float damage , bool ishealth , const MWWorld : : Ptr & object , const MWWorld : : Ptr & attacker , bool successful ) const
void Creature : : onHit ( const MWWorld : : Ptr & ptr , float damage , bool ishealth , const MWWorld : : Ptr & object , const MWWorld : : Ptr & attacker , bool successful ) const
@ -189,18 +360,60 @@ namespace MWClass
ptr . getRefData ( ) . getLocals ( ) . setVarByInt ( script , " onpchitme " , 1 ) ;
ptr . getRefData ( ) . getLocals ( ) . setVarByInt ( script , " onpchitme " , 1 ) ;
}
}
if ( ishealth )
if ( damage > 0.0f & & ! object . isEmpty ( ) )
MWMechanics : : resistNormalWeapon ( ptr , attacker , object , damage ) ;
if ( damage > 0.f )
{
{
if ( damage > 0.0f )
// Check for knockdown
float agilityTerm = getCreatureStats ( ptr ) . getAttribute ( ESM : : Attribute : : Agility ) . getModified ( ) * fKnockDownMult - > getFloat ( ) ;
float knockdownTerm = getCreatureStats ( ptr ) . getAttribute ( ESM : : Attribute : : Agility ) . getModified ( )
* iKnockDownOddsMult - > getInt ( ) * 0.01 + iKnockDownOddsBase - > getInt ( ) ;
int roll = std : : rand ( ) / ( static_cast < double > ( RAND_MAX ) + 1 ) * 100 ; // [0, 99]
if ( ishealth & & agilityTerm < = damage & & knockdownTerm < = roll )
{
getCreatureStats ( ptr ) . setKnockedDown ( true ) ;
}
else
getCreatureStats ( ptr ) . setHitRecovery ( true ) ; // Is this supposed to always occur?
if ( ishealth )
{
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > playSound3D ( ptr , " Health Damage " , 1.0f , 1.0f ) ;
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > playSound3D ( ptr , " Health Damage " , 1.0f , 1.0f ) ;
float health = getCreatureStats ( ptr ) . getHealth ( ) . getCurrent ( ) - damage ;
float health = getCreatureStats ( ptr ) . getHealth ( ) . getCurrent ( ) - damage ;
setActorHealth ( ptr , health , attacker ) ;
setActorHealth ( ptr , health , attacker ) ;
}
else
{
MWMechanics : : DynamicStat < float > fatigue ( getCreatureStats ( ptr ) . getFatigue ( ) ) ;
fatigue . setCurrent ( fatigue . getCurrent ( ) - damage , true ) ;
getCreatureStats ( ptr ) . setFatigue ( fatigue ) ;
}
}
}
else
}
void Creature : : block ( const MWWorld : : Ptr & ptr ) const
{
MWWorld : : InventoryStore & inv = getInventoryStore ( ptr ) ;
MWWorld : : ContainerStoreIterator shield = inv . getSlot ( MWWorld : : InventoryStore : : Slot_CarriedLeft ) ;
if ( shield = = inv . end ( ) )
return ;
MWBase : : SoundManager * sndMgr = MWBase : : Environment : : get ( ) . getSoundManager ( ) ;
switch ( shield - > getClass ( ) . getEquipmentSkill ( * shield ) )
{
{
MWMechanics : : DynamicStat < float > fatigue ( getCreatureStats ( ptr ) . getFatigue ( ) ) ;
case ESM : : Skill : : LightArmor :
fatigue . setCurrent ( fatigue . getCurrent ( ) - damage ) ;
sndMgr - > playSound3D ( ptr , " Light Armor Hit " , 1.0f , 1.0f ) ;
getCreatureStats ( ptr ) . setFatigue ( fatigue ) ;
break ;
case ESM : : Skill : : MediumArmor :
sndMgr - > playSound3D ( ptr , " Medium Armor Hit " , 1.0f , 1.0f ) ;
break ;
case ESM : : Skill : : HeavyArmor :
sndMgr - > playSound3D ( ptr , " Heavy Armor Hit " , 1.0f , 1.0f ) ;
break ;
default :
return ;
}
}
}
}
@ -243,18 +456,33 @@ namespace MWClass
return boost : : shared_ptr < MWWorld : : Action > ( new MWWorld : : ActionTalk ( ptr ) ) ;
return boost : : shared_ptr < MWWorld : : Action > ( new MWWorld : : ActionTalk ( ptr ) ) ;
}
}
MWWorld : : ContainerStore & Creature : : getContainerStore ( const MWWorld : : Ptr & ptr )
MWWorld : : ContainerStore & Creature : : getContainerStore ( const MWWorld : : Ptr & ptr ) const
const
{
{
ensureCustomData ( ptr ) ;
ensureCustomData ( ptr ) ;
return dynamic_cast < CustomData & > ( * ptr . getRefData ( ) . getCustomData ( ) ) . mContainerStore ;
return * dynamic_cast < CustomData & > ( * ptr . getRefData ( ) . getCustomData ( ) ) . mContainerStore ;
}
MWWorld : : InventoryStore & Creature : : getInventoryStore ( const MWWorld : : Ptr & ptr ) const
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
if ( ref - > mBase - > mFlags & ESM : : Creature : : Weapon )
return dynamic_cast < MWWorld : : InventoryStore & > ( getContainerStore ( ptr ) ) ;
else
throw std : : runtime_error ( " this creature has no inventory store " ) ;
}
bool Creature : : hasInventoryStore ( const MWWorld : : Ptr & ptr ) const
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
return ( ref - > mBase - > mFlags & ESM : : Creature : : Weapon ) ;
}
}
std : : string Creature : : getScript ( const MWWorld : : Ptr & ptr ) const
std : : string Creature : : getScript ( const MWWorld : : Ptr & ptr ) const
{
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref =
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
ptr . get < ESM : : Creature > ( ) ;
return ref - > mBase - > mScript ;
return ref - > mBase - > mScript ;
}
}
@ -284,10 +512,51 @@ namespace MWClass
float Creature : : getSpeed ( const MWWorld : : Ptr & ptr ) const
float Creature : : getSpeed ( const MWWorld : : Ptr & ptr ) const
{
{
MWMechanics : : CreatureStats & stats = getCreatureStats ( ptr ) ;
MWMechanics : : CreatureStats & stats = getCreatureStats ( ptr ) ;
float walkSpeed = fMinWalkSpeedCreature - > getFloat ( ) + 0.01 * stats . getAttribute ( ESM : : Attribute : : Speed ) . getModified ( )
float walkSpeed = fMinWalkSpeedCreature - > getFloat ( ) + 0.01 * stats . getAttribute ( ESM : : Attribute : : Speed ) . getModified ( )
* ( fMaxWalkSpeedCreature - > getFloat ( ) - fMinWalkSpeedCreature - > getFloat ( ) ) ;
* ( fMaxWalkSpeedCreature - > getFloat ( ) - fMinWalkSpeedCreature - > getFloat ( ) ) ;
/// \todo what about the rest?
return walkSpeed ;
const MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
const MWMechanics : : MagicEffects & mageffects = stats . getMagicEffects ( ) ;
const float normalizedEncumbrance = getEncumbrance ( ptr ) / getCapacity ( ptr ) ;
bool running = ptr . getClass ( ) . getCreatureStats ( ptr ) . getStance ( MWMechanics : : CreatureStats : : Stance_Run ) ;
float runSpeed = walkSpeed * ( 0.01f * getSkill ( ptr , ESM : : Skill : : Athletics ) *
fAthleticsRunBonus - > getFloat ( ) + fBaseRunMultiplier - > getFloat ( ) ) ;
float moveSpeed ;
if ( normalizedEncumbrance > = 1.0f )
moveSpeed = 0.0f ;
else if ( isFlying ( ptr ) | | ( mageffects . get ( ESM : : MagicEffect : : Levitate ) . mMagnitude > 0 & &
world - > isLevitationEnabled ( ) ) )
{
float flySpeed = 0.01f * ( stats . getAttribute ( ESM : : Attribute : : Speed ) . getModified ( ) +
mageffects . get ( ESM : : MagicEffect : : Levitate ) . mMagnitude ) ;
flySpeed = fMinFlySpeed - > getFloat ( ) + flySpeed * ( fMaxFlySpeed - > getFloat ( ) - fMinFlySpeed - > getFloat ( ) ) ;
flySpeed * = 1.0f - fEncumberedMoveEffect - > getFloat ( ) * normalizedEncumbrance ;
flySpeed = std : : max ( 0.0f , flySpeed ) ;
moveSpeed = flySpeed ;
}
else if ( world - > isSwimming ( ptr ) )
{
float swimSpeed = walkSpeed ;
if ( running )
swimSpeed = runSpeed ;
swimSpeed * = 1.0f + 0.01f * mageffects . get ( ESM : : MagicEffect : : SwiftSwim ) . mMagnitude ;
swimSpeed * = fSwimRunBase - > getFloat ( ) + 0.01f * getSkill ( ptr , ESM : : Skill : : Athletics ) *
fSwimRunAthleticsMult - > getFloat ( ) ;
moveSpeed = swimSpeed ;
}
else if ( running )
moveSpeed = runSpeed ;
else
moveSpeed = walkSpeed ;
if ( getMovementSettings ( ptr ) . mPosition [ 0 ] ! = 0 & & getMovementSettings ( ptr ) . mPosition [ 1 ] = = 0 )
moveSpeed * = 0.75f ;
return moveSpeed ;
}
}
MWMechanics : : Movement & Creature : : getMovementSettings ( const MWWorld : : Ptr & ptr ) const
MWMechanics : : Movement & Creature : : getMovementSettings ( const MWWorld : : Ptr & ptr ) const
@ -413,6 +682,14 @@ namespace MWClass
return MWWorld : : Ptr ( & cell . mCreatures . insert ( * ref ) , & cell ) ;
return MWWorld : : Ptr ( & cell . mCreatures . insert ( * ref ) , & cell ) ;
}
}
bool Creature : : isFlying ( const MWWorld : : Ptr & ptr ) const
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref =
ptr . get < ESM : : Creature > ( ) ;
return ref - > mBase - > mFlags & ESM : : Creature : : Flies ;
}
int Creature : : getSndGenTypeFromName ( const MWWorld : : Ptr & ptr , const std : : string & name )
int Creature : : getSndGenTypeFromName ( const MWWorld : : Ptr & ptr , const std : : string & name )
{
{
if ( name = = " left " )
if ( name = = " left " )
@ -451,6 +728,76 @@ namespace MWClass
throw std : : runtime_error ( std : : string ( " Unexpected soundgen type: " ) + name ) ;
throw std : : runtime_error ( std : : string ( " Unexpected soundgen type: " ) + name ) ;
}
}
int Creature : : getSkill ( const MWWorld : : Ptr & ptr , int skill ) const
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref =
ptr . get < ESM : : Creature > ( ) ;
const ESM : : Skill * skillRecord = MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Skill > ( ) . find ( skill ) ;
switch ( skillRecord - > mData . mSpecialization )
{
case ESM : : Class : : Combat :
return ref - > mBase - > mData . mCombat ;
case ESM : : Class : : Magic :
return ref - > mBase - > mData . mMagic ;
case ESM : : Class : : Stealth :
return ref - > mBase - > mData . mStealth ;
default :
throw std : : runtime_error ( " invalid specialisation " ) ;
}
}
int Creature : : getBloodTexture ( const MWWorld : : Ptr & ptr ) const
{
MWWorld : : LiveCellRef < ESM : : Creature > * ref = ptr . get < ESM : : Creature > ( ) ;
if ( ref - > mBase - > mFlags & ESM : : Creature : : Skeleton )
return 1 ;
if ( ref - > mBase - > mFlags & ESM : : Creature : : Metal )
return 2 ;
return 0 ;
}
void Creature : : readAdditionalState ( const MWWorld : : Ptr & ptr , const ESM : : ObjectState & state )
const
{
const ESM : : CreatureState & state2 = dynamic_cast < const ESM : : CreatureState & > ( state ) ;
ensureCustomData ( ptr ) ;
CustomData & customData = dynamic_cast < CustomData & > ( * ptr . getRefData ( ) . getCustomData ( ) ) ;
customData . mContainerStore - > readState ( state2 . mInventory ) ;
customData . mCreatureStats . readState ( state2 . mCreatureStats ) ;
}
void Creature : : writeAdditionalState ( const MWWorld : : Ptr & ptr , ESM : : ObjectState & state )
const
{
ESM : : CreatureState & state2 = dynamic_cast < ESM : : CreatureState & > ( state ) ;
ensureCustomData ( ptr ) ;
CustomData & customData = dynamic_cast < CustomData & > ( * ptr . getRefData ( ) . getCustomData ( ) ) ;
customData . mContainerStore - > writeState ( state2 . mInventory ) ;
customData . mCreatureStats . writeState ( state2 . mCreatureStats ) ;
}
const ESM : : GameSetting * Creature : : fMinWalkSpeedCreature ;
const ESM : : GameSetting * Creature : : fMinWalkSpeedCreature ;
const ESM : : GameSetting * Creature : : fMaxWalkSpeedCreature ;
const ESM : : GameSetting * Creature : : fMaxWalkSpeedCreature ;
const ESM : : GameSetting * Creature : : fEncumberedMoveEffect ;
const ESM : : GameSetting * Creature : : fSneakSpeedMultiplier ;
const ESM : : GameSetting * Creature : : fAthleticsRunBonus ;
const ESM : : GameSetting * Creature : : fBaseRunMultiplier ;
const ESM : : GameSetting * Creature : : fMinFlySpeed ;
const ESM : : GameSetting * Creature : : fMaxFlySpeed ;
const ESM : : GameSetting * Creature : : fSwimRunBase ;
const ESM : : GameSetting * Creature : : fSwimRunAthleticsMult ;
const ESM : : GameSetting * Creature : : fKnockDownMult ;
const ESM : : GameSetting * Creature : : iKnockDownOddsMult ;
const ESM : : GameSetting * Creature : : iKnockDownOddsBase ;
}
}