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
return;
if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getAiSequence().isInCombat())
return;
MWBase::Environment::get().getWorld()->activate(ptr, MWBase::Environment::get().getWorld()->getPlayerPtr());
}

@ -205,6 +205,8 @@ namespace MWBase
/// Resurrects the player if necessary
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 void togglePOV() = 0;
virtual bool isFirstPerson() const = 0;
virtual void togglePreviewMode(bool enable) = 0;
virtual bool toggleVanityMode(bool enable) = 0;
virtual void allowVanityMode(bool allow) = 0;

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

@ -654,10 +654,11 @@ namespace MWClass
setOnPcHitMe = MWBase::Environment::get().getMechanicsManager()->actorAttacked(ptr, attacker);
}
if(!object.isEmpty())
getCreatureStats(ptr).setLastHitAttemptObject(object.getClass().getId(object));
if(!successful)
{
// TODO: Handle HitAttemptOnMe script function
// Missed
sndMgr->playSound3D(ptr, "miss", 1.0f, 1.0f);
return;
@ -1002,37 +1003,6 @@ namespace MWClass
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
{
ensureCustomData (ptr);

@ -104,9 +104,6 @@ namespace MWClass
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< 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;
///< Return desired movement.

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

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

@ -89,15 +89,22 @@ namespace MWGui
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);
mEditing = false;
mDeleteButton->setVisible (false);
mEffect.mRange = ESM::RT_Self;
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf))
if (!allowSelf)
mEffect.mRange = ESM::RT_Touch;
if (!(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch))
if (!allowTouch)
mEffect.mRange = ESM::RT_Target;
mEffect.mMagnMin = 1;
mEffect.mMagnMax = 1;
@ -118,6 +125,8 @@ namespace MWGui
mMagnitudeMinValue->setCaption("1");
mMagnitudeMaxValue->setCaption("- 1");
mAreaValue->setCaption("0");
setVisible(true);
}
void EditEffectDialog::editEffect (ESM::ENAMstruct effect)
@ -190,26 +199,31 @@ namespace MWGui
{
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
if (mEffect.mRange == ESM::RT_Target && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget))
onRangeButtonClicked(sender);
if (mEffect.mRange == ESM::RT_Self && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf))
onRangeButtonClicked(sender);
if (mEffect.mRange == ESM::RT_Touch && !(mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch))
onRangeButtonClicked(sender);
// does not handle the case where nothing is allowed (this should be prevented before opening the Add Effect dialog)
bool allowSelf = mMagicEffect->mData.mFlags & ESM::MagicEffect::CastSelf;
bool allowTouch = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTouch) && !constantEffect;
bool allowTarget = (mMagicEffect->mData.mFlags & ESM::MagicEffect::CastTarget) && !constantEffect;
if (mEffect.mRange == ESM::RT_Self && !allowSelf)
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)
{
mAreaSlider->setScrollPosition(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();
eventEffectModified(mEffect);
}
@ -542,7 +556,6 @@ namespace MWGui
mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setAttribute (mSelectAttributeDialog->getAttributeId());
mAddEffectDialog.setVisible(true);
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectAttributeDialog);
mSelectAttributeDialog = 0;
}
@ -554,7 +567,6 @@ namespace MWGui
mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setSkill (mSelectSkillDialog->getSkillId());
mAddEffectDialog.setVisible(true);
MWBase::Environment::get().getWindowManager ()->removeDialog (mSelectSkillDialog);
mSelectSkillDialog = 0;
}
@ -611,7 +623,6 @@ namespace MWGui
else
{
mAddEffectDialog.newEffect(effect);
mAddEffectDialog.setVisible(true);
}
}

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

@ -869,13 +869,19 @@ namespace MWMechanics
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);
if(world->isSubmerged(ptr) &&
stats.getMagicEffects().get(ESM::MagicEffect::WaterBreathing).getMagnitude() == 0)
MWBase::World *world = MWBase::Environment::get().getWorld();
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;
if(stats.getFatigue().getCurrent() == 0)
if(knockedOutUnderwater)
stats.setTimeToStartDrowning(0);
else
{
@ -1122,15 +1128,6 @@ namespace MWMechanics
// target lists get updated once every 1.0 sec
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();
int hostilesCount = 0; // need to know this to play Battle music
@ -1563,4 +1560,13 @@ namespace MWMechanics
if (ptr.getClass().isNpc())
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
bool isReadyToBlock(const MWWorld::Ptr& ptr) const;
private:
PtrControllerMap mActors;

@ -92,6 +92,35 @@ MWMechanics::CharacterState runStateToWalkState (MWMechanics::CharacterState sta
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
@ -619,7 +648,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
mAnimation->showWeapons(true);
mAnimation->setWeaponGroup(mCurrentWeapon);
}
mAnimation->showCarriedLeft(mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand);
mAnimation->showCarriedLeft(updateCarriedLeftVisible(mWeaponType));
}
if(!cls.getCreatureStats(mPtr).isDead())
@ -807,6 +837,25 @@ bool CharacterController::updateCreatureState()
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()
{
const MWWorld::Class &cls = mPtr.getClass();
@ -821,10 +870,7 @@ bool CharacterController::updateWeaponState()
{
forcestateupdate = true;
// Shields/torches shouldn't be visible during spellcasting or hand-to-hand
// 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);
mAnimation->showCarriedLeft(updateCarriedLeftVisible(weaptype));
std::string weapgroup;
if(weaptype == WeapType_None)
@ -1250,7 +1296,7 @@ void CharacterController::update(float duration)
const MWWorld::Class &cls = mPtr.getClass();
Ogre::Vector3 movement(0.0f);
updateVisibility();
updateMagicEffects();
if(!cls.isActor())
{
@ -1449,7 +1495,7 @@ void CharacterController::update(float duration)
vec.z = 0.0f;
float height = cls.getCreatureStats(mPtr).land();
float healthLost = cls.getFallDamage(mPtr, height);
float healthLost = getFallDamage(mPtr, height);
if (healthLost > 0.0f)
{
const float fatigueTerm = cls.getCreatureStats(mPtr).getFatigueTerm();
@ -1748,7 +1794,7 @@ void CharacterController::updateContinuousVfx()
}
}
void CharacterController::updateVisibility()
void CharacterController::updateMagicEffects()
{
if (!mPtr.getClass().isActor())
return;
@ -1765,9 +1811,11 @@ void CharacterController::updateVisibility()
{
alpha *= std::max(0.2f, (100.f - chameleon)/100.f);
}
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();
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 updateVisibility();
void updateMagicEffects();
void playDeath(float startpoint, CharacterState death);
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
std::string chooseRandomGroup (const std::string& prefix, int* num = NULL);
bool updateCarriedLeftVisible(WeaponType weaptype) const;
public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController();
@ -224,6 +226,9 @@ public:
void forceStateUpdate();
AiState& getAiState() { return mAiState; }
bool isReadyToBlock() const;
bool isKnockedOut() const;
};
void getWeaponGroup(WeaponType weaptype, std::string &group);

@ -62,17 +62,10 @@ namespace MWMechanics
|| blockerStats.getMagicEffects().get(ESM::MagicEffect::Paralyze).getMagnitude() > 0)
return false;
// Don't block when in spellcasting state (shield is equipped, but not visible)
if (blockerStats.getDrawState() == DrawState_Spell)
if (!MWBase::Environment::get().getMechanicsManager()->isReadyToBlock(blocker))
return false;
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);
if (shield == inv.end() || shield->getTypeName() != typeid(ESM::Armor).name())
return false;

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

@ -52,6 +52,7 @@ namespace MWMechanics
float mFallHeight;
std::string mLastHitObject; // The last object to hit this actor
std::string mLastHitAttemptObject; // The last object to attempt to hit this actor
bool mRecalcMagicka;
@ -241,7 +242,9 @@ namespace MWMechanics
bool getStance (Stance flag) const;
void setLastHitObject(const std::string &objectid);
void setLastHitAttemptObject(const std::string &objectid);
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.
// TODO: Put it somewhere else?

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

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

@ -1352,4 +1352,9 @@ namespace MWMechanics
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 void keepPlayerAlive();
virtual bool isReadyToBlock (const MWWorld::Ptr& ptr) const;
};
}

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

@ -195,6 +195,7 @@ namespace MWRender
MWWorld::InventoryStore &inv = mCharacter.getClass().getInventoryStore(mCharacter);
MWWorld::ContainerStoreIterator iter = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
std::string groupname;
bool showCarriedLeft = true;
if(iter == inv.end())
groupname = "inventoryhandtohand";
else
@ -224,11 +225,15 @@ namespace MWRender
groupname = "inventoryweapontwowide";
else
groupname = "inventoryhandtohand";
}
showCarriedLeft = (iter->getClass().canBeEquipped(*iter, mCharacter).first != 2);
}
else
groupname = "inventoryhandtohand";
}
mAnimation->showCarriedLeft(showCarriedLeft);
mCurrentAnimGroup = groupname;
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]);
return "meshes\\" + sVampireMapping[thisCombination]->mModel;
if (sVampireMapping.find(thisCombination) == sVampireMapping.end())
sVampireMapping[thisCombination] = NULL;
const ESM::BodyPart* bodyPart = sVampireMapping[thisCombination];
if (!bodyPart)
return std::string();
return "meshes\\" + bodyPart->mModel;
}
bool isSkinned (NifOgre::ObjectScenePtr scene)
@ -256,10 +261,15 @@ void NpcAnimation::updateNpcBase()
{
if (isVampire)
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;
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;
@ -399,9 +409,9 @@ void NpcAnimation::updateParts()
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);
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);
}
if(mViewMode == VM_HeadOnly)
@ -973,4 +983,14 @@ void NpcAnimation::equipmentChanged()
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 showWeapons(bool showWeapon);
virtual void showCarriedLeft(bool showa);
virtual void showCarriedLeft(bool show);
virtual void attachArrow();
virtual void releaseArrow();
@ -168,6 +168,8 @@ public:
/// Make the NPC only partially visible
virtual void setAlpha(float alpha);
virtual void setVampire(bool vampire);
/// Prepare this animation for being rendered with \a camera (rotates billboard nodes)
virtual void preRender (Ogre::Camera* camera);
};

@ -433,5 +433,10 @@ op 0x20002c4-0x20002db: ModMagicEffect
op 0x20002dc-0x20002f3: ModMagicEffect, explicit
op 0x20002f4: ResetActors
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)
{
messageBox (message);
}
bool InterpreterContext::menuMode()

@ -78,7 +78,7 @@ namespace MWScript
const std::vector<std::string>& buttons);
virtual void report (const std::string& message);
///< By default echo via messageBox.
///< By default, do nothing.
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
{
static bool sActivate;
@ -703,6 +732,27 @@ namespace MWScript
MWMechanics::CreatureStats &stats = ptr.getClass().getCreatureStats(ptr);
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::opcodeToggleWorld, new OpToggleWorld);
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::opcodeGetPcSleep, new OpGetPcSleep);
interpreter.installSegment5 (Compiler::Misc::opcodeGetPcJumping, new OpGetPcJumping);
@ -1051,6 +1104,8 @@ namespace MWScript
interpreter.installSegment5 (Compiler::Misc::opcodeGetWindSpeed, new OpGetWindSpeed);
interpreter.installSegment5 (Compiler::Misc::opcodeHitOnMe, new OpHitOnMe<ImplicitRef>);
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::opcodeEnableTeleporting, new OpEnableTeleporting<true>);
interpreter.installSegment5 (Compiler::Misc::opcodeShowVars, new OpShowVars<ImplicitRef>);

@ -441,7 +441,8 @@ namespace MWScript
pos.rot[2] = zRot;
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID);
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
{
@ -488,7 +489,8 @@ namespace MWScript
pos.rot[2] = zRot;
MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID);
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:
return;
case 2:
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedLeft, actor);
break;
case 3:
invStore.unequipSlot(MWWorld::InventoryStore::Slot_CarriedRight, actor);
default:
break;
}

@ -180,11 +180,6 @@ namespace MWWorld
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
{
throw std::runtime_error ("movement settings not supported by class");

@ -184,9 +184,6 @@ namespace MWWorld
virtual float getJump(const MWWorld::Ptr &ptr) const;
///< 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;
///< Return desired movement.

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

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

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

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

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

@ -56,6 +56,7 @@ namespace ESM
float mAttackStrength;
float mFallHeight;
std::string mLastHitObject;
std::string mLastHitAttemptObject;
bool mRecalcDynamicStats;
int mDrawState;
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("RootCollisionNode", &construct <NiNode> , RC_RootCollisionNode ));
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("NiZBufferProperty", &construct <NiZBufferProperty> , RC_NiZBufferProperty ));
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
class NiShadeProperty : public Property { };
class NiDitherProperty : public Property { };

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

Loading…
Cancel
Save