Merge remote-tracking branch 'scrawl/master'

moveref
Marc Zinnschlag 10 years ago
commit 33d905dc03

@ -505,6 +505,9 @@ void OMW::Engine::activate()
if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated if (ptr.getClass().getName(ptr) == "") // objects without name presented to user can never be activated
return; return;
if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat())
return;
MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr()); MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
} }

@ -205,6 +205,8 @@ namespace MWBase
/// Resurrects the player if necessary /// Resurrects the player if necessary
virtual void keepPlayerAlive() = 0; virtual void keepPlayerAlive() = 0;
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const = 0;
}; };
} }

@ -388,6 +388,7 @@ namespace MWBase
virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0; virtual bool isOnGround(const MWWorld::Ptr &ptr) const = 0;
virtual void togglePOV() = 0; virtual void togglePOV() = 0;
virtual bool isFirstPerson() const = 0;
virtual void togglePreviewMode(bool enable) = 0; virtual void togglePreviewMode(bool enable) = 0;
virtual bool toggleVanityMode(bool enable) = 0; virtual bool toggleVanityMode(bool enable) = 0;
virtual void allowVanityMode(bool allow) = 0; virtual void allowVanityMode(bool allow) = 0;

@ -346,10 +346,11 @@ namespace MWClass
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
} }
if(!object.isEmpty())
getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object));
if(!successful) if(!successful)
{ {
// TODO: Handle HitAttemptOnMe script function
// Missed // Missed
MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f); MWBase::Environment::get().getSoundManager()->playSound3D(ptr, "miss", 1.0f, 1.0f);
return; return;
@ -674,13 +675,12 @@ namespace MWClass
std::vector<const ESM::SoundGenerator*> sounds; std::vector<const ESM::SoundGenerator*> sounds;
sounds.reserve(8); sounds.reserve(8);
std::string ptrid = Creature::getId(ptr); MWWorld::LiveCellRef<ESM::Creature>* ref = ptr.get<ESM::Creature>();
MWWorld::Store<ESM::SoundGenerator>::iterator sound = store.begin(); MWWorld::Store<ESM::SoundGenerator>::iterator sound = store.begin();
while(sound != store.end()) while(sound != store.end())
{ {
if(type == sound->mType && !sound->mCreature.empty() && if (type == sound->mType && !sound->mCreature.empty() && Misc::StringUtils::ciEqual(ref->mBase->mOriginal, sound->mCreature))
Misc::StringUtils::ciEqual(ptrid.substr(0, sound->mCreature.size()),
sound->mCreature))
sounds.push_back(&*sound); sounds.push_back(&*sound);
++sound; ++sound;
} }

@ -654,10 +654,11 @@ namespace MWClass
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker); setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
} }
if(!object.isEmpty())
getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object));
if(!successful) if(!successful)
{ {
// TODO: Handle HitAttemptOnMe script function
// Missed // Missed
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f); sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
return; return;
@ -1002,37 +1003,6 @@ namespace MWClass
return x; return x;
} }
float Npc::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
const float fallDistanceMin = store.find("fFallDamageDistanceMin")->getFloat();
if (fallHeight >= fallDistanceMin)
{
const float acrobaticsSkill = ptr.getClass().getNpcStats (ptr).getSkill(ESM::Skill::Acrobatics).getModified();
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
const float jumpSpellBonus = npcdata->mNpcStats.getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude();
const float fallAcroBase = store.find("fFallAcroBase")->getFloat();
const float fallAcroMult = store.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = store.find("fFallDistanceBase")->getFloat();
const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat();
float x = fallHeight - fallDistanceMin;
x -= (1.5 * acrobaticsSkill) + jumpSpellBonus;
x = std::max(0.0f, x);
float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill);
x = fallDistanceBase + fallDistanceMult * x;
x *= a;
return x;
}
return 0;
}
MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const MWMechanics::Movement& Npc::getMovementSettings (const MWWorld::Ptr& ptr) const
{ {
ensureCustomData (ptr); ensureCustomData (ptr);

@ -104,9 +104,6 @@ namespace MWClass
virtual float getJump(const MWWorld::Ptr &ptr) const; virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement) ///< Return jump velocity (not accounting for movement)
virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const;
///< Return amount of health points lost when falling
virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const; virtual MWMechanics::Movement& getMovementSettings (const MWWorld::Ptr& ptr) const;
///< Return desired movement. ///< Return desired movement.

@ -227,7 +227,7 @@ namespace MWDialogue
success = false; success = false;
} }
if (!success && mScriptVerbose) if (!success)
{ {
std::cerr std::cerr
<< "compiling failed (dialogue script)" << std::endl << "compiling failed (dialogue script)" << std::endl

@ -109,8 +109,8 @@ namespace MWGui
mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge())); mCharge->setCaption(boost::lexical_cast<std::string>(mEnchanting.getGemCharge()));
std::stringstream castCost; std::stringstream castCost;
castCost << std::setprecision(1) << std::fixed << mEnchanting.getCastCost(); castCost << mEnchanting.getCastCost();
mCastCost->setCaption(boost::lexical_cast<std::string>(castCost.str())); mCastCost->setCaption(castCost.str());
mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice())); mPrice->setCaption(boost::lexical_cast<std::string>(mEnchanting.getEnchantPrice()));

@ -89,15 +89,22 @@ namespace MWGui
void EditEffectDialog::newEffect (const ESM::MagicEffect *effect) void EditEffectDialog::newEffect (const ESM::MagicEffect *effect)
{ {
bool allowSelf = effect->mData.mFlags & ESM::MagicEffect::CastSelf;
bool allowTouch = (effect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect;
bool allowTarget = (effect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect;
if (!allowSelf && !allowTouch && !allowTarget)
return; // TODO: Show an error message popup?
setMagicEffect(effect); setMagicEffect(effect);
mEditing = false; mEditing = false;
mDeleteButton->setVisible (false); mDeleteButton->setVisible (false);
mEffect.mRange = ESM::RT_Self; mEffect.mRange = ESM::RT_Self;
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf)) if (!allowSelf)
mEffect.mRange = ESM::RT_Touch; mEffect.mRange = ESM::RT_Touch;
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch)) if (!allowTouch)
mEffect.mRange = ESM::RT_Target; mEffect.mRange = ESM::RT_Target;
mEffect.mMagnMin = 1; mEffect.mMagnMin = 1;
mEffect.mMagnMax = 1; mEffect.mMagnMax = 1;
@ -118,6 +125,8 @@ namespace MWGui
mMagnitudeMinValue->setCaption("1"); mMagnitudeMinValue->setCaption("1");
mMagnitudeMaxValue->setCaption("- 1"); mMagnitudeMaxValue->setCaption("- 1");
mAreaValue->setCaption("0"); mAreaValue->setCaption("0");
setVisible(true);
} }
void EditEffectDialog::editEffect (ESM::ENAMstruct effect) void EditEffectDialog::editEffect (ESM::ENAMstruct effect)
@ -190,26 +199,31 @@ namespace MWGui
{ {
mEffect.mRange = (mEffect.mRange+1)%3; mEffect.mRange = (mEffect.mRange+1)%3;
if (mEffect.mRange == ESM::RT_Self)
mRangeButton->setCaptionWithReplacing ("#{sRangeSelf}");
else if (mEffect.mRange == ESM::RT_Target)
mRangeButton->setCaptionWithReplacing ("#{sRangeTarget}");
else if (mEffect.mRange == ESM::RT_Touch)
mRangeButton->setCaptionWithReplacing ("#{sRangeTouch}");
// cycle through range types until we find something that's allowed // cycle through range types until we find something that's allowed
if (mEffect.mRange == ESM::RT_Target && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget)) // does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog)
onRangeButtonClicked(sender); bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf;
if (mEffect.mRange == ESM::RT_Self && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf)) bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect;
onRangeButtonClicked(sender); bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect;
if (mEffect.mRange == ESM::RT_Touch && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch)) if (mEffect.mRange == ESM::RT_Self && !allowSelf)
onRangeButtonClicked(sender); mEffect.mRange = (mEffect.mRange+1)%3;
if (mEffect.mRange == ESM::RT_Touch && !allowTouch)
mEffect.mRange = (mEffect.mRange+1)%3;
if (mEffect.mRange == ESM::RT_Target && !allowTarget)
mEffect.mRange = (mEffect.mRange+1)%3;
if(mEffect.mRange == ESM::RT_Self) if(mEffect.mRange == ESM::RT_Self)
{ {
mAreaSlider->setScrollPosition(0); mAreaSlider->setScrollPosition(0);
onAreaChanged(mAreaSlider,0); onAreaChanged(mAreaSlider,0);
} }
if (mEffect.mRange == ESM::RT_Self)
mRangeButton->setCaptionWithReplacing ("#{sRangeSelf}");
else if (mEffect.mRange == ESM::RT_Target)
mRangeButton->setCaptionWithReplacing ("#{sRangeTarget}");
else if (mEffect.mRange == ESM::RT_Touch)
mRangeButton->setCaptionWithReplacing ("#{sRangeTouch}");
updateBoxes(); updateBoxes();
eventEffectModified(mEffect); eventEffectModified(mEffect);
} }
@ -542,7 +556,6 @@ namespace MWGui
mAddEffectDialog.newEffect(effect); mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setAttribute (mSelectAttributeDialog->getAttributeId()); mAddEffectDialog.setAttribute (mSelectAttributeDialog->getAttributeId());
mAddEffectDialog.setVisible(true);
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectAttributeDialog); MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectAttributeDialog);
mSelectAttributeDialog = 0; mSelectAttributeDialog = 0;
} }
@ -554,7 +567,6 @@ namespace MWGui
mAddEffectDialog.newEffect(effect); mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setSkill (mSelectSkillDialog->getSkillId()); mAddEffectDialog.setSkill (mSelectSkillDialog->getSkillId());
mAddEffectDialog.setVisible(true);
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectSkillDialog); MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectSkillDialog);
mSelectSkillDialog = 0; mSelectSkillDialog = 0;
} }
@ -611,7 +623,6 @@ namespace MWGui
else else
{ {
mAddEffectDialog.newEffect(effect); mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setVisible(true);
} }
} }

@ -444,6 +444,7 @@ namespace MWGui
mVideoBackground->setVisible(false); mVideoBackground->setVisible(false);
mHud->setVisible(mHudEnabled && mGuiEnabled); mHud->setVisible(mHudEnabled && mGuiEnabled);
mToolTips->setVisible(mGuiEnabled);
bool gameMode = !isGuiMode(); bool gameMode = !isGuiMode();
@ -587,16 +588,11 @@ namespace MWGui
mJournal->setVisible(true); mJournal->setVisible(true);
break; break;
case GM_LoadingWallpaper: case GM_LoadingWallpaper:
mHud->setVisible(false);
setCursorVisible(false);
break;
case GM_Loading: case GM_Loading:
// Show the pinned windows // Don't need to show anything here - GM_LoadingWallpaper covers everything else anyway,
mMap->setVisible(mMap->pinned() && !(mForceHidden & GW_Map)); // GM_Loading uses a texture of the last rendered frame so everything previously visible will be rendered.
mStatsWindow->setVisible(mStatsWindow->pinned() && !(mForceHidden & GW_Stats)); mHud->setVisible(false);
mInventoryWindow->setVisible(mInventoryWindow->pinned() && !(mForceHidden & GW_Inventory)); mToolTips->setVisible(false);
mSpellWindow->setVisible(mSpellWindow->pinned() && !(mForceHidden & GW_Magic));
setCursorVisible(false); setCursorVisible(false);
break; break;
default: default:

@ -869,13 +869,19 @@ namespace MWMechanics
void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration) void Actors::updateDrowning(const MWWorld::Ptr& ptr, float duration)
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); PtrControllerMap::iterator it = mActors.find(ptr);
if (it == mActors.end())
return;
CharacterController* ctrl = it->second;
NpcStats &stats = ptr.getClass().getNpcStats(ptr); NpcStats &stats = ptr.getClass().getNpcStats(ptr);
if(world->isSubmerged(ptr) && MWBase::World *world = MWBase::Environment::get().getWorld();
stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0) bool knockedOutUnderwater = (ctrl->isKnockedOut() && world->isUnderwater(ptr.getCell(), Ogre::Vector3(ptr.getRefData().getPosition().pos)));
if((world->isSubmerged(ptr) || knockedOutUnderwater)
&& stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0)
{ {
float timeLeft = 0.0f; float timeLeft = 0.0f;
if(stats.getFatigue().getCurrent() == 0) if(knockedOutUnderwater)
stats.setTimeToStartDrowning(0); stats.setTimeToStartDrowning(0);
else else
{ {
@ -1122,15 +1128,6 @@ namespace MWMechanics
// target lists get updated once every 1.0 sec // target lists get updated once every 1.0 sec
if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0; if (timerUpdateAITargets >= 1.0f) timerUpdateAITargets = 0;
// Reset data from previous frame
for (PtrControllerMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
// Reset last hit object, which is only valid for one frame
// Note, the new hit object for this frame may be set by CharacterController::update -> Animation::runAnimation
// (below)
iter->first.getClass().getCreatureStats(iter->first).setLastHitObject(std::string());
}
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
int hostilesCount = 0; // need to know this to play Battle music int hostilesCount = 0; // need to know this to play Battle music
@ -1563,4 +1560,13 @@ namespace MWMechanics
if (ptr.getClass().isNpc()) if (ptr.getClass().isNpc())
calculateNpcStatModifiers(ptr, 0.f); calculateNpcStatModifiers(ptr, 0.f);
} }
bool Actors::isReadyToBlock(const MWWorld::Ptr &ptr) const
{
PtrControllerMap::const_iterator it = mActors.find(ptr);
if (it == mActors.end())
return false;
return it->second->isReadyToBlock();
}
} }

@ -125,6 +125,8 @@ namespace MWMechanics
void clear(); // Clear death counter void clear(); // Clear death counter
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
private: private:
PtrControllerMap mActors; PtrControllerMap mActors;

@ -92,6 +92,35 @@ MWMechanics::CharacterState runStateToWalkState (MWMechanics::CharacterState sta
return ret; return ret;
} }
float getFallDamage(const MWWorld::Ptr& ptr, float fallHeight)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
const float fallDistanceMin = store.find("fFallDamageDistanceMin")->getFloat();
if (fallHeight >= fallDistanceMin)
{
const float acrobaticsSkill = ptr.getClass().getSkill(ptr, ESM::Skill::Acrobatics);
const float jumpSpellBonus = ptr.getClass().getCreatureStats(ptr).getMagicEffects().get(ESM::MagicEffect::Jump).getMagnitude();
const float fallAcroBase = store.find("fFallAcroBase")->getFloat();
const float fallAcroMult = store.find("fFallAcroMult")->getFloat();
const float fallDistanceBase = store.find("fFallDistanceBase")->getFloat();
const float fallDistanceMult = store.find("fFallDistanceMult")->getFloat();
float x = fallHeight - fallDistanceMin;
x -= (1.5 * acrobaticsSkill) + jumpSpellBonus;
x = std::max(0.0f, x);
float a = fallAcroBase + fallAcroMult * (100 - acrobaticsSkill);
x = fallDistanceBase + fallDistanceMult * x;
x *= a;
return x;
}
return 0.f;
}
} }
namespace MWMechanics namespace MWMechanics
@ -619,7 +648,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
mAnimation->showWeapons(true); mAnimation->showWeapons(true);
mAnimation->setWeaponGroup(mCurrentWeapon); mAnimation->setWeaponGroup(mCurrentWeapon);
} }
mAnimation->showCarriedLeft(mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand);
mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType));
} }
if(!cls.getCreatureStats(mPtr).isDead()) if(!cls.getCreatureStats(mPtr).isDead())
@ -807,6 +837,25 @@ bool CharacterController::updateCreatureState()
return false; return false;
} }
bool CharacterController::updateCarriedLeftVisible(WeaponType weaptype) const
{
// Shields/torches shouldn't be visible during any operation involving two hands
// There seems to be no text keys for this purpose, except maybe for "[un]equip start/stop",
// but they are also present in weapon drawing animation.
switch (weaptype)
{
case WeapType_Spell:
case WeapType_BowAndArrow:
case WeapType_Crossbow:
case WeapType_HandToHand:
case WeapType_TwoHand:
case WeapType_TwoWide:
return false;
default:
return true;
}
}
bool CharacterController::updateWeaponState() bool CharacterController::updateWeaponState()
{ {
const MWWorld::Class &cls = mPtr.getClass(); const MWWorld::Class &cls = mPtr.getClass();
@ -821,10 +870,7 @@ bool CharacterController::updateWeaponState()
{ {
forcestateupdate = true; forcestateupdate = true;
// Shields/torches shouldn't be visible during spellcasting or hand-to-hand mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
// 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.
mAnimation->showCarriedLeft(weaptype != WeapType_Spell && weaptype != WeapType_HandToHand);
std::string weapgroup; std::string weapgroup;
if(weaptype == WeapType_None) if(weaptype == WeapType_None)
@ -1250,7 +1296,7 @@ void CharacterController::update(float duration)
const MWWorld::Class &cls = mPtr.getClass(); const MWWorld::Class &cls = mPtr.getClass();
Ogre::Vector3 movement(0.0f); Ogre::Vector3 movement(0.0f);
updateVisibility(); updateMagicEffects();
if(!cls.isActor()) if(!cls.isActor())
{ {
@ -1449,7 +1495,7 @@ void CharacterController::update(float duration)
vec.z = 0.0f; vec.z = 0.0f;
float height = cls.getCreatureStats(mPtr).land(); float height = cls.getCreatureStats(mPtr).land();
float healthLost = cls.getFallDamage(mPtr, height); float healthLost = getFallDamage(mPtr, height);
if (healthLost > 0.0f) if (healthLost > 0.0f)
{ {
const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm(); const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
@ -1748,7 +1794,7 @@ void CharacterController::updateContinuousVfx()
} }
} }
void CharacterController::updateVisibility() void CharacterController::updateMagicEffects()
{ {
if (!mPtr.getClass().isActor()) if (!mPtr.getClass().isActor())
return; return;
@ -1765,9 +1811,11 @@ void CharacterController::updateVisibility()
{ {
alpha *= std::max(0.2f, (100.f - chameleon)/100.f); alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
} }
mAnimation->setAlpha(alpha); mAnimation->setAlpha(alpha);
bool vampire = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Vampirism).getMagnitude() > 0.0f;
mAnimation->setVampire(vampire);
float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude(); float light = mPtr.getClass().getCreatureStats(mPtr).getMagicEffects().get(ESM::MagicEffect::Light).getMagnitude();
mAnimation->setLightEffect(light); mAnimation->setLightEffect(light);
} }
@ -1787,4 +1835,14 @@ void CharacterController::determineAttackType()
} }
} }
bool CharacterController::isReadyToBlock() const
{
return updateCarriedLeftVisible(mWeaponType);
}
bool CharacterController::isKnockedOut() const
{
return mHitState == CharState_KnockOut;
}
} }

@ -190,7 +190,7 @@ class CharacterController
void castSpell(const std::string& spellid); void castSpell(const std::string& spellid);
void updateVisibility(); void updateMagicEffects();
void playDeath(float startpoint, CharacterState death); void playDeath(float startpoint, CharacterState death);
void playRandomDeath(float startpoint = 0.0f); void playRandomDeath(float startpoint = 0.0f);
@ -199,6 +199,8 @@ class CharacterController
/// @param num if non-NULL, the chosen animation number will be written here /// @param num if non-NULL, the chosen animation number will be written here
std::string chooseRandomGroup (const std::string& prefix, int* num = NULL); std::string chooseRandomGroup (const std::string& prefix, int* num = NULL);
bool updateCarriedLeftVisible(WeaponType weaptype) const;
public: public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();
@ -224,6 +226,9 @@ public:
void forceStateUpdate(); void forceStateUpdate();
AiState& getAiState() { return mAiState; } AiState& getAiState() { return mAiState; }
bool isReadyToBlock() const;
bool isKnockedOut() const;
}; };
void getWeaponGroup(WeaponType weaptype, std::string &group); void getWeaponGroup(WeaponType weaptype, std::string &group);

@ -62,17 +62,10 @@ namespace MWMechanics
|| blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0) || blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
return false; return false;
// Don't block when in spellcasting state (shield is equipped, but not visible) if (!MWBase::Environment::get().getMechanicsManager()->isReadyToBlock(blocker))
if (blockerStats.getDrawState() == DrawState_Spell)
return false; return false;
MWWorld::InventoryStore& inv = blocker.getClass().getInventoryStore(blocker); MWWorld::InventoryStore& inv = blocker.getClass().getInventoryStore(blocker);
// Don't block when in hand-to-hand combat (shield is equipped, but not visible)
if (blockerStats.getDrawState() == DrawState_Weapon &&
inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight) == inv.end())
return false;
MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); MWWorld::ContainerStoreIterator shield = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft);
if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name()) if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name())
return false; return false;

@ -359,6 +359,16 @@ namespace MWMechanics
return mLastHitObject; return mLastHitObject;
} }
void CreatureStats::setLastHitAttemptObject(const std::string& objectid)
{
mLastHitAttemptObject = objectid;
}
const std::string &CreatureStats::getLastHitAttemptObject() const
{
return mLastHitAttemptObject;
}
void CreatureStats::addToFallHeight(float height) void CreatureStats::addToFallHeight(float height)
{ {
mFallHeight += height; mFallHeight += height;
@ -510,6 +520,7 @@ namespace MWMechanics
state.mAttackStrength = mAttackStrength; state.mAttackStrength = mAttackStrength;
state.mFallHeight = mFallHeight; // TODO: vertical velocity (move from PhysicActor to CreatureStats?) state.mFallHeight = mFallHeight; // TODO: vertical velocity (move from PhysicActor to CreatureStats?)
state.mLastHitObject = mLastHitObject; state.mLastHitObject = mLastHitObject;
state.mLastHitAttemptObject = mLastHitAttemptObject;
state.mRecalcDynamicStats = mRecalcMagicka; state.mRecalcDynamicStats = mRecalcMagicka;
state.mDrawState = mDrawState; state.mDrawState = mDrawState;
state.mLevel = mLevel; state.mLevel = mLevel;
@ -558,6 +569,7 @@ namespace MWMechanics
mAttackStrength = state.mAttackStrength; mAttackStrength = state.mAttackStrength;
mFallHeight = state.mFallHeight; mFallHeight = state.mFallHeight;
mLastHitObject = state.mLastHitObject; mLastHitObject = state.mLastHitObject;
mLastHitAttemptObject = state.mLastHitAttemptObject;
mRecalcMagicka = state.mRecalcDynamicStats; mRecalcMagicka = state.mRecalcDynamicStats;
mDrawState = DrawState_(state.mDrawState); mDrawState = DrawState_(state.mDrawState);
mLevel = state.mLevel; mLevel = state.mLevel;

@ -52,6 +52,7 @@ namespace MWMechanics
float mFallHeight; float mFallHeight;
std::string mLastHitObject; // The last object to hit this actor std::string mLastHitObject; // The last object to hit this actor
std::string mLastHitAttemptObject; // The last object to attempt to hit this actor
bool mRecalcMagicka; bool mRecalcMagicka;
@ -241,7 +242,9 @@ namespace MWMechanics
bool getStance (Stance flag) const; bool getStance (Stance flag) const;
void setLastHitObject(const std::string &objectid); void setLastHitObject(const std::string &objectid);
void setLastHitAttemptObject(const std::string &objectid);
const std::string &getLastHitObject() const; const std::string &getLastHitObject() const;
const std::string &getLastHitAttemptObject() const;
// Note, this is just a cache to avoid checking the whole container store every frame. We don't need to store it in saves. // Note, this is just a cache to avoid checking the whole container store every frame. We don't need to store it in saves.
// TODO: Put it somewhere else? // TODO: Put it somewhere else?

@ -55,7 +55,7 @@ namespace MWMechanics
enchantment.mData.mCharge = getGemCharge(); enchantment.mData.mCharge = getGemCharge();
enchantment.mData.mAutocalc = 0; enchantment.mData.mAutocalc = 0;
enchantment.mData.mType = mCastStyle; enchantment.mData.mType = mCastStyle;
enchantment.mData.mCost = getEnchantPoints(); enchantment.mData.mCost = getCastCost();
store.remove(mSoulGemPtr, 1, player); store.remove(mSoulGemPtr, 1, player);
@ -156,7 +156,7 @@ namespace MWMechanics
* *
* Formula on UESPWiki is not entirely correct. * Formula on UESPWiki is not entirely correct.
*/ */
float Enchanting::getEnchantPoints() const int Enchanting::getEnchantPoints() const
{ {
if (mEffectList.mList.empty()) if (mEffectList.mList.empty())
// No effects added, cost = 0 // No effects added, cost = 0
@ -195,11 +195,11 @@ namespace MWMechanics
--effectsLeftCnt; --effectsLeftCnt;
} }
return enchantmentCost; return static_cast<int>(enchantmentCost);
} }
float Enchanting::getCastCost() const int Enchanting::getCastCost() const
{ {
if (mCastStyle == ESM::Enchantment::ConstantEffect) if (mCastStyle == ESM::Enchantment::ConstantEffect)
return 0; return 0;
@ -215,7 +215,7 @@ namespace MWMechanics
*/ */
const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10); const float castCost = enchantCost - (enchantCost / 100) * (eSkill - 10);
return (castCost < 1) ? 1 : castCost; return static_cast<int>((castCost < 1) ? 1 : castCost);
} }
@ -240,7 +240,7 @@ namespace MWMechanics
return soul->mData.mSoul; return soul->mData.mSoul;
} }
float Enchanting::getMaxEnchantValue() const int Enchanting::getMaxEnchantValue() const
{ {
if (itemEmpty()) if (itemEmpty())
return 0; return 0;

@ -35,10 +35,10 @@ namespace MWMechanics
bool create(); //Return true if created, false if failed. bool create(); //Return true if created, false if failed.
void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object) void nextCastStyle(); //Set enchant type to next possible type (for mOldItemPtr object)
int getCastStyle() const; int getCastStyle() const;
float getEnchantPoints() const; int getEnchantPoints() const;
float getCastCost() const; int getCastCost() const;
int getEnchantPrice() const; int getEnchantPrice() const;
float getMaxEnchantValue() const; int getMaxEnchantValue() const;
int getGemCharge() const; int getGemCharge() const;
float getEnchantChance() const; float getEnchantChance() const;
bool soulEmpty() const; //Return true if empty bool soulEmpty() const; //Return true if empty

@ -1352,4 +1352,9 @@ namespace MWMechanics
stats.resurrect(); stats.resurrect();
} }
} }
bool MechanicsManager::isReadyToBlock(const MWWorld::Ptr &ptr) const
{
return mActors.isReadyToBlock(ptr);
}
} }

@ -169,6 +169,8 @@ namespace MWMechanics
virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false); virtual bool isAggressive (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target, int bias=0, bool ignoreDistance=false);
virtual void keepPlayerAlive(); virtual void keepPlayerAlive();
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
}; };
} }

@ -228,6 +228,7 @@ public:
virtual void preRender (Ogre::Camera* camera); virtual void preRender (Ogre::Camera* camera);
virtual void setAlpha(float alpha) {} virtual void setAlpha(float alpha) {}
virtual void setVampire(bool vampire) {}
public: public:
void updatePtr(const MWWorld::Ptr &ptr); void updatePtr(const MWWorld::Ptr &ptr);

@ -195,6 +195,7 @@ 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;
bool showCarriedLeft = true;
if(iter == inv.end()) if(iter == inv.end())
groupname = "inventoryhandtohand"; groupname = "inventoryhandtohand";
else else
@ -224,11 +225,15 @@ namespace MWRender
groupname = "inventoryweapontwowide"; groupname = "inventoryweapontwowide";
else else
groupname = "inventoryhandtohand"; groupname = "inventoryhandtohand";
}
showCarriedLeft = (iter->getClass().canBeEquipped(*iter, mCharacter).first != 2);
}
else else
groupname = "inventoryhandtohand"; groupname = "inventoryhandtohand";
} }
mAnimation->showCarriedLeft(showCarriedLeft);
mCurrentAnimGroup = groupname; mCurrentAnimGroup = groupname;
mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->play(mCurrentAnimGroup, 1, Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0);

@ -56,8 +56,13 @@ std::string getVampireHead(const std::string& race, bool female)
} }
} }
assert(sVampireMapping[thisCombination]); if (sVampireMapping.find(thisCombination) == sVampireMapping.end())
return "meshes\\" + sVampireMapping[thisCombination]->mModel; sVampireMapping[thisCombination] = NULL;
const ESM::BodyPart* bodyPart = sVampireMapping[thisCombination];
if (!bodyPart)
return std::string();
return "meshes\\" + bodyPart->mModel;
} }
bool isSkinned (NifOgre::ObjectScenePtr scene) bool isSkinned (NifOgre::ObjectScenePtr scene)
@ -256,10 +261,15 @@ void NpcAnimation::updateNpcBase()
{ {
if (isVampire) if (isVampire)
mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female); mHeadModel = getVampireHead(mNpc->mRace, mNpc->mFlags & ESM::NPC::Female);
else else if (!mNpc->mHead.empty())
mHeadModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHead)->mModel; mHeadModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHead)->mModel;
else
mHeadModel = "";
mHairModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHair)->mModel; if (!mNpc->mHair.empty())
mHairModel = "meshes\\" + store.get<ESM::BodyPart>().find(mNpc->mHair)->mModel;
else
mHairModel = "";
} }
bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0; bool isBeast = (race->mData.mFlags & ESM::Race::Beast) != 0;
@ -399,9 +409,9 @@ void NpcAnimation::updateParts()
if(mViewMode != VM_FirstPerson) if(mViewMode != VM_FirstPerson)
{ {
if(mPartPriorities[ESM::PRT_Head] < 1) if(mPartPriorities[ESM::PRT_Head] < 1 && !mHeadModel.empty())
addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel); addOrReplaceIndividualPart(ESM::PRT_Head, -1,1, mHeadModel);
if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1) if(mPartPriorities[ESM::PRT_Hair] < 1 && mPartPriorities[ESM::PRT_Head] <= 1 && !mHairModel.empty())
addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel); addOrReplaceIndividualPart(ESM::PRT_Hair, -1,1, mHairModel);
} }
if(mViewMode == VM_HeadOnly) if(mViewMode == VM_HeadOnly)
@ -973,4 +983,14 @@ void NpcAnimation::equipmentChanged()
updateParts(); updateParts();
} }
void NpcAnimation::setVampire(bool vampire)
{
if (mNpcType == Type_Werewolf) // we can't have werewolf vampires, can we
return;
if ((mNpcType == Type_Vampire) != vampire)
{
rebuild();
}
}
} }

@ -143,7 +143,7 @@ public:
virtual void setPitchFactor(float factor) { mPitchFactor = factor; } virtual void setPitchFactor(float factor) { mPitchFactor = factor; }
virtual void showWeapons(bool showWeapon); virtual void showWeapons(bool showWeapon);
virtual void showCarriedLeft(bool showa); virtual void showCarriedLeft(bool show);
virtual void attachArrow(); virtual void attachArrow();
virtual void releaseArrow(); virtual void releaseArrow();
@ -168,6 +168,8 @@ public:
/// Make the NPC only partially visible /// Make the NPC only partially visible
virtual void setAlpha(float alpha); virtual void setAlpha(float alpha);
virtual void setVampire(bool vampire);
/// Prepare this animation for being rendered with \a camera (rotates billboard nodes) /// Prepare this animation for being rendered with \a camera (rotates billboard nodes)
virtual void preRender (Ogre::Camera* camera); virtual void preRender (Ogre::Camera* camera);
}; };

@ -433,5 +433,10 @@ op 0x20002c4-0x20002db: ModMagicEffect
op 0x20002dc-0x20002f3: ModMagicEffect, explicit op 0x20002dc-0x20002f3: ModMagicEffect, explicit
op 0x20002f4: ResetActors op 0x20002f4: ResetActors
op 0x20002f5: ToggleWorld op 0x20002f5: ToggleWorld
op 0x20002f6: PCForce1stPerson
op 0x20002f7: PCForce3rdPerson
op 0x20002f8: PCGet3rdPerson
op 0x20002f9: HitAttemptOnMe
op 0x20002fa: HitAttemptOnMe, explicit
opcodes 0x20002f6-0x3ffffff unused opcodes 0x20002fb-0x3ffffff unused

@ -205,7 +205,6 @@ namespace MWScript
void InterpreterContext::report (const std::string& message) void InterpreterContext::report (const std::string& message)
{ {
messageBox (message);
} }
bool InterpreterContext::menuMode() bool InterpreterContext::menuMode()

@ -78,7 +78,7 @@ namespace MWScript
const std::vector<std::string>& buttons); const std::vector<std::string>& buttons);
virtual void report (const std::string& message); virtual void report (const std::string& message);
///< By default echo via messageBox. ///< By default, do nothing.
virtual bool menuMode(); virtual bool menuMode();

@ -312,6 +312,35 @@ namespace MWScript
} }
}; };
class OpPcForce1stPerson : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
if (!MWBase::Environment::get().getWorld()->isFirstPerson())
MWBase::Environment::get().getWorld()->togglePOV();
}
};
class OpPcForce3rdPerson : public Interpreter::Opcode0
{
virtual void execute (Interpreter::Runtime& runtime)
{
if (MWBase::Environment::get().getWorld()->isFirstPerson())
MWBase::Environment::get().getWorld()->togglePOV();
}
};
class OpPcGet3rdPerson : public Interpreter::Opcode0
{
public:
virtual void execute(Interpreter::Runtime& runtime)
{
runtime.push(!MWBase::Environment::get().getWorld()->isFirstPerson());
}
};
class OpToggleVanityMode : public Interpreter::Opcode0 class OpToggleVanityMode : public Interpreter::Opcode0
{ {
static bool sActivate; static bool sActivate;
@ -703,6 +732,27 @@ namespace MWScript
MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr); MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
runtime.push(::Misc::StringUtils::ciEqual(objectID, stats.getLastHitObject())); runtime.push(::Misc::StringUtils::ciEqual(objectID, stats.getLastHitObject()));
stats.setLastHitObject(std::string());
}
};
template <class R>
class OpHitAttemptOnMe : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
MWWorld::Ptr ptr = R()(runtime);
std::string objectID = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop();
MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
runtime.push(::Misc::StringUtils::ciEqual(objectID, stats.getLastHitAttemptObject()));
stats.setLastHitAttemptObject(std::string());
} }
}; };
@ -1002,6 +1052,9 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeToggleWater, new OpToggleWater); interpreter.installSegment5 (Compiler::Misc::opcodeToggleWater, new OpToggleWater);
interpreter.installSegment5 (Compiler::Misc::opcodeToggleWorld, new OpToggleWorld); interpreter.installSegment5 (Compiler::Misc::opcodeToggleWorld, new OpToggleWorld);
interpreter.installSegment5 (Compiler::Misc::opcodeDontSaveObject, new OpDontSaveObject); interpreter.installSegment5 (Compiler::Misc::opcodeDontSaveObject, new OpDontSaveObject);
interpreter.installSegment5 (Compiler::Misc::opcodePcForce1stPerson, new OpPcForce1stPerson);
interpreter.installSegment5 (Compiler::Misc::opcodePcForce3rdPerson, new OpPcForce3rdPerson);
interpreter.installSegment5 (Compiler::Misc::opcodePcGet3rdPerson, new OpPcGet3rdPerson);
interpreter.installSegment5 (Compiler::Misc::opcodeToggleVanityMode, new OpToggleVanityMode); interpreter.installSegment5 (Compiler::Misc::opcodeToggleVanityMode, new OpToggleVanityMode);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcSleep, new OpGetPcSleep); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcSleep, new OpGetPcSleep);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcJumping, new OpGetPcJumping); interpreter.installSegment5 (Compiler::Misc::opcodeGetPcJumping, new OpGetPcJumping);
@ -1051,6 +1104,8 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeGetWindSpeed, new OpGetWindSpeed); interpreter.installSegment5 (Compiler::Misc::opcodeGetWindSpeed, new OpGetWindSpeed);
interpreter.installSegment5 (Compiler::Misc::opcodeHitOnMe, new OpHitOnMe<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeHitOnMe, new OpHitOnMe<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeHitOnMeExplicit, new OpHitOnMe<ExplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeHitOnMeExplicit, new OpHitOnMe<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeHitAttemptOnMe, new OpHitAttemptOnMe<ImplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeHitAttemptOnMeExplicit, new OpHitAttemptOnMe<ExplicitRef>);
interpreter.installSegment5 (Compiler::Misc::opcodeDisableTeleporting, new OpEnableTeleporting<false>); interpreter.installSegment5 (Compiler::Misc::opcodeDisableTeleporting, new OpEnableTeleporting<false>);
interpreter.installSegment5 (Compiler::Misc::opcodeEnableTeleporting, new OpEnableTeleporting<true>); interpreter.installSegment5 (Compiler::Misc::opcodeEnableTeleporting, new OpEnableTeleporting<true>);
interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars<ImplicitRef>); interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars<ImplicitRef>);

@ -441,7 +441,8 @@ namespace MWScript
pos.rot[2] = zRot; pos.rot[2] = zRot;
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID);
ref.getPtr().getCellRef().setPosition(pos); ref.getPtr().getCellRef().setPosition(pos);
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos);
placed.getClass().adjustPosition(placed, true);
} }
else else
{ {
@ -488,7 +489,8 @@ namespace MWScript
pos.rot[2] = zRot; pos.rot[2] = zRot;
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID);
ref.getPtr().getCellRef().setPosition(pos); ref.getPtr().getCellRef().setPosition(pos);
MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos); MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos);
placed.getClass().adjustPosition(placed, true);
} }
}; };

@ -31,11 +31,7 @@ namespace MWWorld
{ {
case 0: case 0:
return; return;
case 2: default:
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft, actor);
break;
case 3:
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, actor);
break; break;
} }

@ -180,11 +180,6 @@ namespace MWWorld
throw std::runtime_error ("class does not support enchanting"); throw std::runtime_error ("class does not support enchanting");
} }
float Class::getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const
{
return 0;
}
MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const
{ {
throw std::runtime_error ("movement settings not supported by class"); throw std::runtime_error ("movement settings not supported by class");

@ -184,9 +184,6 @@ namespace MWWorld
virtual float getJump(const MWWorld::Ptr &ptr) const; virtual float getJump(const MWWorld::Ptr &ptr) const;
///< Return jump velocity (not accounting for movement) ///< Return jump velocity (not accounting for movement)
virtual float getFallDamage(const MWWorld::Ptr &ptr, float fallHeight) const;
///< Return amount of health points lost when falling
virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const; virtual MWMechanics::Movement& getMovementSettings (const Ptr& ptr) const;
///< Return desired movement. ///< Return desired movement.

@ -255,11 +255,7 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor)
{ {
case 0: case 0:
continue; continue;
case 2: default:
slots_[MWWorld::InventoryStore::Slot_CarriedLeft] = end();
break;
case 3:
// Prefer keeping twohanded weapon
break; break;
} }

@ -452,6 +452,10 @@ namespace MWWorld
mRendering->togglePOV(); mRendering->togglePOV();
} }
virtual bool isFirstPerson() const {
return mRendering->getCamera()->isFirstPerson();
}
virtual void togglePreviewMode(bool enable) { virtual void togglePreviewMode(bool enable) {
mRendering->togglePreviewMode(enable); mRendering->togglePreviewMode(enable);
} }

@ -116,7 +116,7 @@ namespace Compiler
extensions.registerInstruction ("additem", "clX", opcodeAddItem, opcodeAddItemExplicit); extensions.registerInstruction ("additem", "clX", opcodeAddItem, opcodeAddItemExplicit);
extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount, extensions.registerFunction ("getitemcount", 'l', "c", opcodeGetItemCount,
opcodeGetItemCountExplicit); opcodeGetItemCountExplicit);
extensions.registerInstruction ("removeitem", "cl", opcodeRemoveItem, extensions.registerInstruction ("removeitem", "clX", opcodeRemoveItem,
opcodeRemoveItemExplicit); opcodeRemoveItemExplicit);
extensions.registerInstruction ("equip", "cX", opcodeEquip, opcodeEquipExplicit); extensions.registerInstruction ("equip", "cX", opcodeEquip, opcodeEquipExplicit);
extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit); extensions.registerFunction ("getarmortype", 'l', "l", opcodeGetArmorType, opcodeGetArmorTypeExplicit);
@ -261,6 +261,9 @@ namespace Compiler
extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid); extensions.registerInstruction ("togglepathgrid", "", opcodeTogglePathgrid);
extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid); extensions.registerInstruction ("tpg", "", opcodeTogglePathgrid);
extensions.registerInstruction ("dontsaveobject", "", opcodeDontSaveObject); extensions.registerInstruction ("dontsaveobject", "", opcodeDontSaveObject);
extensions.registerInstruction ("pcforce1stperson", "", opcodePcForce1stPerson);
extensions.registerInstruction ("pcforce3rdperson", "", opcodePcForce3rdPerson);
extensions.registerFunction ("pcget3rdperson", 'l', "", opcodePcGet3rdPerson);
extensions.registerInstruction ("togglevanitymode", "", opcodeToggleVanityMode); extensions.registerInstruction ("togglevanitymode", "", opcodeToggleVanityMode);
extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode); extensions.registerInstruction ("tvm", "", opcodeToggleVanityMode);
extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep); extensions.registerFunction ("getpcsleep", 'l', "", opcodeGetPcSleep);
@ -292,6 +295,7 @@ namespace Compiler
extensions.registerInstruction ("hurtcollidingactor", "f", opcodeHurtCollidingActor, opcodeHurtCollidingActorExplicit); extensions.registerInstruction ("hurtcollidingactor", "f", opcodeHurtCollidingActor, opcodeHurtCollidingActorExplicit);
extensions.registerFunction ("getwindspeed", 'f', "", opcodeGetWindSpeed); extensions.registerFunction ("getwindspeed", 'f', "", opcodeGetWindSpeed);
extensions.registerFunction ("hitonme", 'l', "S", opcodeHitOnMe, opcodeHitOnMeExplicit); extensions.registerFunction ("hitonme", 'l', "S", opcodeHitOnMe, opcodeHitOnMeExplicit);
extensions.registerFunction ("hitattemptonme", 'l', "S", opcodeHitAttemptOnMe, opcodeHitAttemptOnMeExplicit);
extensions.registerInstruction ("disableteleporting", "", opcodeDisableTeleporting); extensions.registerInstruction ("disableteleporting", "", opcodeDisableTeleporting);
extensions.registerInstruction ("enableteleporting", "", opcodeEnableTeleporting); extensions.registerInstruction ("enableteleporting", "", opcodeEnableTeleporting);
extensions.registerInstruction ("showvars", "", opcodeShowVars, opcodeShowVarsExplicit); extensions.registerInstruction ("showvars", "", opcodeShowVars, opcodeShowVarsExplicit);

@ -215,6 +215,9 @@ namespace Compiler
const int opcodeToggleWorld = 0x20002f5; const int opcodeToggleWorld = 0x20002f5;
const int opcodeTogglePathgrid = 0x2000146; const int opcodeTogglePathgrid = 0x2000146;
const int opcodeDontSaveObject = 0x2000153; const int opcodeDontSaveObject = 0x2000153;
const int opcodePcForce1stPerson = 0x20002f6;
const int opcodePcForce3rdPerson = 0x20002f7;
const int opcodePcGet3rdPerson = 0x20002f8;
const int opcodeToggleVanityMode = 0x2000174; const int opcodeToggleVanityMode = 0x2000174;
const int opcodeGetPcSleep = 0x200019f; const int opcodeGetPcSleep = 0x200019f;
const int opcodeGetPcJumping = 0x2000233; const int opcodeGetPcJumping = 0x2000233;
@ -266,6 +269,8 @@ namespace Compiler
const int opcodePayFineThief = 0x2000237; const int opcodePayFineThief = 0x2000237;
const int opcodeHitOnMe = 0x2000213; const int opcodeHitOnMe = 0x2000213;
const int opcodeHitOnMeExplicit = 0x2000214; const int opcodeHitOnMeExplicit = 0x2000214;
const int opcodeHitAttemptOnMe = 0x20002f9;
const int opcodeHitAttemptOnMeExplicit = 0x20002fa;
const int opcodeDisableTeleporting = 0x2000215; const int opcodeDisableTeleporting = 0x2000215;
const int opcodeEnableTeleporting = 0x2000216; const int opcodeEnableTeleporting = 0x2000216;
const int opcodeShowVars = 0x200021d; const int opcodeShowVars = 0x200021d;

@ -68,6 +68,8 @@ void ESM::CreatureStats::load (ESMReader &esm)
mLastHitObject = esm.getHNOString ("LHIT"); mLastHitObject = esm.getHNOString ("LHIT");
mLastHitAttemptObject = esm.getHNOString ("LHAT");
mRecalcDynamicStats = false; mRecalcDynamicStats = false;
esm.getHNOT (mRecalcDynamicStats, "CALC"); esm.getHNOT (mRecalcDynamicStats, "CALC");
@ -179,6 +181,9 @@ void ESM::CreatureStats::save (ESMWriter &esm) const
if (!mLastHitObject.empty()) if (!mLastHitObject.empty())
esm.writeHNString ("LHIT", mLastHitObject); esm.writeHNString ("LHIT", mLastHitObject);
if (!mLastHitAttemptObject.empty())
esm.writeHNString ("LHAT", mLastHitAttemptObject);
if (mRecalcDynamicStats) if (mRecalcDynamicStats)
esm.writeHNT ("CALC", mRecalcDynamicStats); esm.writeHNT ("CALC", mRecalcDynamicStats);

@ -56,6 +56,7 @@ namespace ESM
float mAttackStrength; float mAttackStrength;
float mFallHeight; float mFallHeight;
std::string mLastHitObject; std::string mLastHitObject;
std::string mLastHitAttemptObject;
bool mRecalcDynamicStats; bool mRecalcDynamicStats;
int mDrawState; int mDrawState;
unsigned char mDeathAnimation; unsigned char mDeathAnimation;

@ -57,6 +57,7 @@ static std::map<std::string,RecordFactoryEntry> makeFactory()
newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera )); newFactory.insert(makeEntry("NiCamera", &construct <NiCamera> , RC_NiCamera ));
newFactory.insert(makeEntry("RootCollisionNode", &construct <NiNode> , RC_RootCollisionNode )); newFactory.insert(makeEntry("RootCollisionNode", &construct <NiNode> , RC_RootCollisionNode ));
newFactory.insert(makeEntry("NiTexturingProperty", &construct <NiTexturingProperty> , RC_NiTexturingProperty )); newFactory.insert(makeEntry("NiTexturingProperty", &construct <NiTexturingProperty> , RC_NiTexturingProperty ));
newFactory.insert(makeEntry("NiFogProperty", &construct <NiFogProperty> , RC_NiFogProperty ));
newFactory.insert(makeEntry("NiMaterialProperty", &construct <NiMaterialProperty> , RC_NiMaterialProperty )); newFactory.insert(makeEntry("NiMaterialProperty", &construct <NiMaterialProperty> , RC_NiMaterialProperty ));
newFactory.insert(makeEntry("NiZBufferProperty", &construct <NiZBufferProperty> , RC_NiZBufferProperty )); newFactory.insert(makeEntry("NiZBufferProperty", &construct <NiZBufferProperty> , RC_NiZBufferProperty ));
newFactory.insert(makeEntry("NiAlphaProperty", &construct <NiAlphaProperty> , RC_NiAlphaProperty )); newFactory.insert(makeEntry("NiAlphaProperty", &construct <NiAlphaProperty> , RC_NiAlphaProperty ));

@ -155,6 +155,22 @@ public:
} }
}; };
class NiFogProperty : public Property
{
public:
float mFogDepth;
Ogre::Vector3 mColour;
void read(NIFStream *nif)
{
Property::read(nif);
mFogDepth = nif->getFloat();
mColour = nif->getVector3();
}
};
// These contain no other data than the 'flags' field in Property // These contain no other data than the 'flags' field in Property
class NiShadeProperty : public Property { }; class NiShadeProperty : public Property { };
class NiDitherProperty : public Property { }; class NiDitherProperty : public Property { };

@ -44,6 +44,7 @@ enum RecordType
RC_NiBSParticleNode, RC_NiBSParticleNode,
RC_NiCamera, RC_NiCamera,
RC_NiTexturingProperty, RC_NiTexturingProperty,
RC_NiFogProperty,
RC_NiMaterialProperty, RC_NiMaterialProperty,
RC_NiZBufferProperty, RC_NiZBufferProperty,
RC_NiAlphaProperty, RC_NiAlphaProperty,

Loading…
Cancel
Save