Merge branch 'master' of github.com:OpenMW/openmw

deque
MiroslavR 10 years ago
commit ff74d54e98

@ -1,37 +1,26 @@
os:
- linux
- osx
language: cpp language: cpp
compiler:
- gcc
branches: branches:
only: only:
- master - master
- /openmw-.*$/ - /openmw-.*$/
before_install: before_install:
- pwd - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
- sudo apt-get update -qq
- sudo apt-get install -qq libgtest-dev google-mock
- sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1
- sudo make -j4
- sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
- sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
before_script: before_script:
- cd - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_script.linux.sh; fi
- mkdir build - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
- cd build
- cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE
script: script:
- cd ./build
- make -j4 - make -j4
after_script: after_script:
- ./openmw_test_suite - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
notifications: notifications:
recipients: recipients:
- lgromanowski+travis.ci@gmail.com - lgromanowski+travis.ci@gmail.com
- corrmage+travis-ci@gmail.com
email: email:
on_success: change on_success: change
on_failure: always on_failure: always

@ -0,0 +1,18 @@
#!/bin/sh
export CXX=g++
export CC=gcc
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
sudo apt-get update -qq
sudo apt-get install -qq libgtest-dev google-mock
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build
sudo cmake .. -DBUILD_SHARED_LIBS=1
sudo make -j4
sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so

@ -0,0 +1,9 @@
#!/bin/sh
export CXX=clang++
export CC=clang
brew tap openmw/openmw
brew update
brew unlink boost
brew install cmake openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg pkg-config qt unshield

@ -0,0 +1,5 @@
#!/bin/sh
mkdir build
cd build
cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE

@ -0,0 +1,5 @@
#!/bin/sh
mkdir build
cd build
cmake -DCMAKE_FRAMEWORK_PATH="/usr/local/lib/macosx/Release" -DCMAKE_EXE_LINKER_FLAGS="-F/usr/local/lib/macosx/Release" -DCMAKE_CXX_FLAGS="-stdlib=libstdc++" -DCMAKE_BUILD_TYPE=Debug -DBUILD_MYGUI_PLUGIN=OFF -G"Unix Makefiles" ..

@ -541,6 +541,8 @@ namespace MWBase
/// Resets all actors in the current active cells to their original location within that cell. /// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors() = 0; virtual void resetActors() = 0;
virtual bool isWalkingOnWater (const MWWorld::Ptr& actor) = 0;
}; };
} }

@ -230,7 +230,7 @@ namespace MWClass
const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat(); const float fFatigueAttackMult = gmst.find("fFatigueAttackMult")->getFloat();
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat(); const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
MWMechanics::DynamicStat<float> fatigue = stats.getFatigue(); MWMechanics::DynamicStat<float> fatigue = stats.getFatigue();
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
if (!weapon.isEmpty()) if (!weapon.isEmpty())
fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult; fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult;
@ -537,7 +537,7 @@ namespace MWClass
const MWBase::World *world = MWBase::Environment::get().getWorld(); const MWBase::World *world = MWBase::Environment::get().getWorld();
const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects(); const MWMechanics::MagicEffects &mageffects = stats.getMagicEffects();
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run); bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
@ -738,7 +738,7 @@ namespace MWClass
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
if(world->isUnderwater(ptr.getCell(), pos)) if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
return 2; return 2;
if(world->isOnGround(ptr)) if(world->isOnGround(ptr))
return 0; return 0;
@ -748,7 +748,7 @@ namespace MWClass
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
if(world->isUnderwater(ptr.getCell(), pos)) if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
return 3; return 3;
if(world->isOnGround(ptr)) if(world->isOnGround(ptr))
return 1; return 1;

@ -302,11 +302,11 @@ namespace MWClass
Misc::StringUtils::toLower(faction); Misc::StringUtils::toLower(faction);
if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) if(ref->mBase->mNpdtType != ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS)
{ {
data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt52.mRank; data->mNpcStats.setFactionRank(faction, (int)ref->mBase->mNpdt52.mRank);
} }
else else
{ {
data->mNpcStats.getFactionRanks()[faction] = (int)ref->mBase->mNpdt12.mRank; data->mNpcStats.setFactionRank(faction, (int)ref->mBase->mNpdt12.mRank);
} }
} }
@ -495,7 +495,7 @@ namespace MWClass
const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat(); const float fFatigueAttackMult = store.find("fFatigueAttackMult")->getFloat();
const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat(); const float fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat();
MWMechanics::DynamicStat<float> fatigue = getCreatureStats(ptr).getFatigue(); MWMechanics::DynamicStat<float> fatigue = getCreatureStats(ptr).getFatigue();
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
if (!weapon.isEmpty()) if (!weapon.isEmpty())
fatigueLoss += weapon.getClass().getWeight(weapon) * getNpcStats(ptr).getAttackStrength() * fWeaponFatigueMult; fatigueLoss += weapon.getClass().getWeight(weapon) * getNpcStats(ptr).getAttackStrength() * fWeaponFatigueMult;
@ -914,7 +914,7 @@ namespace MWClass
const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData()); const NpcCustomData *npcdata = static_cast<const NpcCustomData*>(ptr.getRefData().getCustomData());
const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects(); const MWMechanics::MagicEffects &mageffects = npcdata->mNpcStats.getMagicEffects();
const float normalizedEncumbrance = Npc::getEncumbrance(ptr) / Npc::getCapacity(ptr); const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
bool sneaking = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak); bool sneaking = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Sneak);
bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run); bool running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
@ -930,7 +930,7 @@ namespace MWClass
gmst.fAthleticsRunBonus->getFloat() + gmst.fBaseRunMultiplier->getFloat()); gmst.fAthleticsRunBonus->getFloat() + gmst.fBaseRunMultiplier->getFloat());
float moveSpeed; float moveSpeed;
if(normalizedEncumbrance >= 1.0f) if(getEncumbrance(ptr) > getCapacity(ptr))
moveSpeed = 0.0f; moveSpeed = 0.0f;
else if(mageffects.get(ESM::MagicEffect::Levitate).getMagnitude() > 0 && else if(mageffects.get(ESM::MagicEffect::Levitate).getMagnitude() > 0 &&
world->isLevitationEnabled()) world->isLevitationEnabled())
@ -1225,7 +1225,7 @@ namespace MWClass
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
if(world->isSwimming(ptr)) if(world->isSwimming(ptr))
return "Swim Left"; return "Swim Left";
if(world->isUnderwater(ptr.getCell(), pos)) if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
return "FootWaterLeft"; return "FootWaterLeft";
if(world->isOnGround(ptr)) if(world->isOnGround(ptr))
{ {
@ -1252,7 +1252,7 @@ namespace MWClass
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
if(world->isSwimming(ptr)) if(world->isSwimming(ptr))
return "Swim Right"; return "Swim Right";
if(world->isUnderwater(ptr.getCell(), pos)) if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
return "FootWaterRight"; return "FootWaterRight";
if(world->isOnGround(ptr)) if(world->isOnGround(ptr))
{ {
@ -1277,7 +1277,7 @@ namespace MWClass
{ {
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos); Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
if(world->isUnderwater(ptr.getCell(), pos)) if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
return "DefaultLandWater"; return "DefaultLandWater";
if(world->isOnGround(ptr)) if(world->isOnGround(ptr))
return "Body Fall Medium"; return "Body Fall Medium";

@ -68,7 +68,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
return false; return false;
MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats (mActor); MWMechanics::NpcStats& stats = mActor.getClass().getNpcStats (mActor);
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find ( Misc::StringUtils::lowerCase (info.mFaction)); std::map<std::string, int>::const_iterator iter = stats.getFactionRanks().find ( Misc::StringUtils::lowerCase (info.mFaction));
if (iter==stats.getFactionRanks().end()) if (iter==stats.getFactionRanks().end())
return false; return false;
@ -112,7 +112,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
if (!info.mPcFaction.empty()) if (!info.mPcFaction.empty())
{ {
MWMechanics::NpcStats& stats = player.getClass().getNpcStats (player); MWMechanics::NpcStats& stats = player.getClass().getNpcStats (player);
std::map<std::string,int>::iterator iter = stats.getFactionRanks().find (Misc::StringUtils::lowerCase (info.mPcFaction)); std::map<std::string,int>::const_iterator iter = stats.getFactionRanks().find (Misc::StringUtils::lowerCase (info.mPcFaction));
if(iter==stats.getFactionRanks().end()) if(iter==stats.getFactionRanks().end())
return false; return false;
@ -379,7 +379,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
if (mActor.getClass().getNpcStats (mActor).getFactionRanks().empty()) if (mActor.getClass().getNpcStats (mActor).getFactionRanks().empty())
return 0; return 0;
std::pair<std::string, int> faction = const std::pair<std::string, int> faction =
*mActor.getClass().getNpcStats (mActor).getFactionRanks().begin(); *mActor.getClass().getNpcStats (mActor).getFactionRanks().begin();
int rank = getFactionRank (player, faction.first); int rank = getFactionRank (player, faction.first);

@ -333,7 +333,8 @@ namespace MWGui
float e1 = 0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified(); float e1 = 0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).getModified();
float f1 = 0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified(); float f1 = 0.2f * sellerStats.getAttribute(ESM::Attribute::Personality).getModified();
float pcTerm = (clampedDisposition - 50 + a1 + b1 + c1) * playerStats.getFatigueTerm(); float dispositionTerm = gmst.find("fDispositionMod")->getFloat() * (clampedDisposition - 50);
float pcTerm = (dispositionTerm - 50 + a1 + b1 + c1) * playerStats.getFatigueTerm();
float npcTerm = (d1 + e1 + f1) * sellerStats.getFatigueTerm(); float npcTerm = (d1 + e1 + f1) * sellerStats.getFatigueTerm();
float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat(); float x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat();
if (buying) if (buying)

@ -385,7 +385,7 @@ namespace MWInput
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
mOverencumberedMessageDelay -= dt; mOverencumberedMessageDelay -= dt;
if (player.getClass().getEncumbrance(player) >= player.getClass().getCapacity(player)) if (player.getClass().getEncumbrance(player) > player.getClass().getCapacity(player))
{ {
mPlayer->setAutoMove (false); mPlayer->setAutoMove (false);
if (mOverencumberedMessageDelay <= 0) if (mOverencumberedMessageDelay <= 0)

@ -445,9 +445,7 @@ namespace MWMechanics
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified (); int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
float capacity = ptr.getClass().getCapacity(ptr); float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
float encumbrance = ptr.getClass().getEncumbrance(ptr);
float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
if (normalizedEncumbrance > 1) if (normalizedEncumbrance > 1)
normalizedEncumbrance = 1; normalizedEncumbrance = 1;
@ -1447,6 +1445,8 @@ namespace MWMechanics
continue; continue;
if (followTarget == actor) if (followTarget == actor)
list.push_back(iter->first); list.push_back(iter->first);
else
break;
} }
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat) else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
break; break;

@ -1428,7 +1428,9 @@ void CharacterController::update(float duration)
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>(); const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat(); const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->getFloat();
const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat(); const float fatigueJumpMult = gmst.find("fFatigueJumpMult")->getFloat();
const float normalizedEncumbrance = cls.getEncumbrance(mPtr) / cls.getCapacity(mPtr); float normalizedEncumbrance = mPtr.getClass().getNormalizedEncumbrance(mPtr);
if (normalizedEncumbrance > 1)
normalizedEncumbrance = 1;
const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult; const int fatigueDecrease = fatigueJumpBase + (1 - normalizedEncumbrance) * fatigueJumpMult;
DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue(); DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease); fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);

@ -124,7 +124,7 @@ namespace MWMechanics
const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->getFloat(); const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->getFloat();
const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->getFloat(); const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->getFloat();
MWMechanics::DynamicStat<float> fatigue = blockerStats.getFatigue(); MWMechanics::DynamicStat<float> fatigue = blockerStats.getFatigue();
float normalizedEncumbrance = blocker.getClass().getEncumbrance(blocker) / blocker.getClass().getCapacity(blocker); float normalizedEncumbrance = blocker.getClass().getNormalizedEncumbrance(blocker);
normalizedEncumbrance = std::min(1.f, normalizedEncumbrance); normalizedEncumbrance = std::min(1.f, normalizedEncumbrance);
float fatigueLoss = fFatigueBlockBase + normalizedEncumbrance * fFatigueBlockMult; float fatigueLoss = fFatigueBlockBase + normalizedEncumbrance * fFatigueBlockMult;
fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult; fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult;

@ -69,9 +69,41 @@ const std::map<std::string, int>& MWMechanics::NpcStats::getFactionRanks() const
return mFactionRank; return mFactionRank;
} }
std::map<std::string, int>& MWMechanics::NpcStats::getFactionRanks() void MWMechanics::NpcStats::raiseRank(const std::string &faction)
{ {
return mFactionRank; const std::string lower = Misc::StringUtils::lowerCase(faction);
std::map<std::string, int>::iterator it = mFactionRank.find(lower);
if (it != mFactionRank.end())
{
// Does the next rank exist?
const ESM::Faction* faction = MWBase::Environment::get().getWorld()->getStore().get<ESM::Faction>().find(lower);
if (it->second+1 < 10 && !faction->mRanks[it->second+1].empty())
it->second += 1;
}
}
void MWMechanics::NpcStats::lowerRank(const std::string &faction)
{
const std::string lower = Misc::StringUtils::lowerCase(faction);
std::map<std::string, int>::iterator it = mFactionRank.find(lower);
if (it != mFactionRank.end())
{
it->second = std::max(0, it->second-1);
}
}
void MWMechanics::NpcStats::setFactionRank(const std::string &faction, int rank)
{
const std::string lower = Misc::StringUtils::lowerCase(faction);
mFactionRank[lower] = rank;
}
void MWMechanics::NpcStats::joinFaction(const std::string& faction)
{
const std::string lower = Misc::StringUtils::lowerCase(faction);
std::map<std::string, int>::iterator it = mFactionRank.find(lower);
if (it == mFactionRank.end())
mFactionRank[lower] = 0;
} }
bool MWMechanics::NpcStats::getExpelled(const std::string& factionID) const bool MWMechanics::NpcStats::getExpelled(const std::string& factionID) const

@ -70,7 +70,15 @@ namespace MWMechanics
SkillValue& getSkill (int index); SkillValue& getSkill (int index);
const std::map<std::string, int>& getFactionRanks() const; const std::map<std::string, int>& getFactionRanks() const;
std::map<std::string, int>& getFactionRanks(); /// Increase the rank in this faction by 1, if such a rank exists.
void raiseRank(const std::string& faction);
/// Lower the rank in this faction by 1, if such a rank exists.
void lowerRank(const std::string& faction);
/// Join this faction, setting the initial rank to 0.
void joinFaction(const std::string& faction);
/// Warning: this function performs no check whether the rank exists,
/// and should be used in initial actor setup only.
void setFactionRank(const std::string& faction, int rank);
const std::set<std::string>& getExpelled() const { return mExpelled; } const std::set<std::string>& getExpelled() const { return mExpelled; }
bool getExpelled(const std::string& factionID) const; bool getExpelled(const std::string& factionID) const;

@ -774,7 +774,7 @@ namespace MWMechanics
static const float fFatigueSpellBase = store.get<ESM::GameSetting>().find("fFatigueSpellBase")->getFloat(); static const float fFatigueSpellBase = store.get<ESM::GameSetting>().find("fFatigueSpellBase")->getFloat();
static const float fFatigueSpellMult = store.get<ESM::GameSetting>().find("fFatigueSpellMult")->getFloat(); static const float fFatigueSpellMult = store.get<ESM::GameSetting>().find("fFatigueSpellMult")->getFloat();
DynamicStat<float> fatigue = stats.getFatigue(); DynamicStat<float> fatigue = stats.getFatigue();
const float normalizedEncumbrance = mCaster.getClass().getEncumbrance(mCaster) / mCaster.getClass().getCapacity(mCaster); const float normalizedEncumbrance = mCaster.getClass().getNormalizedEncumbrance(mCaster);
float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult); float fatigueLoss = spell->mData.mCost * (fFatigueSpellBase + normalizedEncumbrance * fFatigueSpellMult);
fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue); fatigue.setCurrent(fatigue.getCurrent() - fatigueLoss); stats.setFatigue(fatigue);

@ -728,7 +728,7 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co
{ {
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx; MWBase::SoundManager::PlayType type = MWBase::SoundManager::Play_TypeSfx;
if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0) if(evt.compare(10, evt.size()-10, "left") == 0 || evt.compare(10, evt.size()-10, "right") == 0 || evt.compare(10, evt.size()-10, "land") == 0)
type = MWBase::SoundManager::Play_TypeFoot; type = MWBase::SoundManager::Play_TypeFoot;
sndMgr->playSound3D(mPtr, sound, volume, pitch, type); sndMgr->playSound3D(mPtr, sound, volume, pitch, type);
} }

@ -250,7 +250,6 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store)
mObjects->buildStaticGeometry (*store); mObjects->buildStaticGeometry (*store);
sh::Factory::getInstance().unloadUnreferencedMaterials(); sh::Factory::getInstance().unloadUnreferencedMaterials();
mDebugging->cellAdded(store); mDebugging->cellAdded(store);
waterAdded(store);
} }
void RenderingManager::addObject (const MWWorld::Ptr& ptr){ void RenderingManager::addObject (const MWWorld::Ptr& ptr){
@ -421,18 +420,12 @@ void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt)
mOcclusionQuery->setActive(false); mOcclusionQuery->setActive(false);
} }
void RenderingManager::waterAdded (MWWorld::CellStore *store) void RenderingManager::setWaterEnabled(bool enable)
{ {
if (store->getCell()->mData.mFlags & ESM::Cell::HasWater) mWater->setActive(enable);
{
mWater->changeCell (store->getCell());
mWater->setActive(true);
}
else
removeWater();
} }
void RenderingManager::setWaterHeight(const float height) void RenderingManager::setWaterHeight(float height)
{ {
mWater->setHeight(height); mWater->setHeight(height);
} }

@ -100,7 +100,6 @@ public:
/// \todo this function should be removed later. Instead the rendering subsystems should track /// \todo this function should be removed later. Instead the rendering subsystems should track
/// when rebatching is needed and update automatically at the end of each frame. /// when rebatching is needed and update automatically at the end of each frame.
void cellAdded (MWWorld::CellStore *store); void cellAdded (MWWorld::CellStore *store);
void waterAdded(MWWorld::CellStore *store);
/// Clear all savegame-specific data (i.e. fog of war textures) /// Clear all savegame-specific data (i.e. fog of war textures)
void clear(); void clear();
@ -121,7 +120,8 @@ public:
/// Updates an object's rotation /// Updates an object's rotation
void rotateObject (const MWWorld::Ptr& ptr); void rotateObject (const MWWorld::Ptr& ptr);
void setWaterHeight(const float height); void setWaterHeight(float height);
void setWaterEnabled(bool enabled);
bool toggleWater(); bool toggleWater();
bool toggleWorld(); bool toggleWorld();

@ -81,7 +81,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor)
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat(); const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
MWMechanics::CreatureStats& attackerStats = actor.getClass().getCreatureStats(actor); MWMechanics::CreatureStats& attackerStats = actor.getClass().getCreatureStats(actor);
MWMechanics::DynamicStat<float> fatigue = attackerStats.getFatigue(); MWMechanics::DynamicStat<float> fatigue = attackerStats.getFatigue();
const float normalizedEncumbrance = actor.getClass().getEncumbrance(actor) / actor.getClass().getCapacity(actor); const float normalizedEncumbrance = actor.getClass().getNormalizedEncumbrance(actor);
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult; float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
if (!weapon->isEmpty()) if (!weapon->isEmpty())
fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult; fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult;

@ -290,18 +290,15 @@ namespace MWScript
const std::string &name = runtime.getStringLiteral (runtime[0].mInteger); const std::string &name = runtime.getStringLiteral (runtime[0].mInteger);
runtime.pop(); runtime.pop();
int count = 0;
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore (ptr); MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore (ptr);
for (MWWorld::ContainerStoreIterator it = invStore.begin(MWWorld::ContainerStore::Type_Miscellaneous); for (MWWorld::ContainerStoreIterator it = invStore.begin(MWWorld::ContainerStore::Type_Miscellaneous);
it != invStore.end(); ++it) it != invStore.end(); ++it)
{ {
if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), name)) if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), name))
{ ++count;
runtime.push(1);
return;
}
} }
runtime.push(0); runtime.push(count);
} }
}; };

@ -310,7 +310,7 @@ namespace MWScript
std::string InterpreterContext::getNPCRank() const std::string InterpreterContext::getNPCRank() const
{ {
std::map<std::string, int> ranks = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks(); const std::map<std::string, int>& ranks = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks();
std::map<std::string, int>::const_iterator it = ranks.begin(); std::map<std::string, int>::const_iterator it = ranks.begin();
MWBase::World *world = MWBase::Environment::get().getWorld(); MWBase::World *world = MWBase::Environment::get().getWorld();
@ -348,7 +348,7 @@ namespace MWScript
std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first; std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first;
std::map<std::string, int> ranks = player.getClass().getNpcStats (player).getFactionRanks(); const std::map<std::string, int>& ranks = player.getClass().getNpcStats (player).getFactionRanks();
std::map<std::string, int>::const_iterator it = ranks.find(factionId); std::map<std::string, int>::const_iterator it = ranks.find(factionId);
int rank = -1; int rank = -1;
if (it != ranks.end()) if (it != ranks.end())
@ -375,7 +375,7 @@ namespace MWScript
std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first; std::string factionId = getReferenceImp().getClass().getNpcStats (getReferenceImp()).getFactionRanks().begin()->first;
std::map<std::string, int> ranks = player.getClass().getNpcStats (player).getFactionRanks(); const std::map<std::string, int>& ranks = player.getClass().getNpcStats (player).getFactionRanks();
std::map<std::string, int>::const_iterator it = ranks.find(factionId); std::map<std::string, int>::const_iterator it = ranks.find(factionId);
int rank = -1; int rank = -1;
if (it != ranks.end()) if (it != ranks.end())

@ -548,10 +548,7 @@ namespace MWScript
if(factionID != "") if(factionID != "")
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) == player.getClass().getNpcStats(player).getFactionRanks().end()) player.getClass().getNpcStats(player).joinFaction(factionID);
{
player.getClass().getNpcStats(player).getFactionRanks()[factionID] = 0;
}
} }
} }
}; };
@ -585,13 +582,11 @@ namespace MWScript
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) == player.getClass().getNpcStats(player).getFactionRanks().end()) if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) == player.getClass().getNpcStats(player).getFactionRanks().end())
{ {
player.getClass().getNpcStats(player).getFactionRanks()[factionID] = 0; player.getClass().getNpcStats(player).joinFaction(factionID);
} }
else else
{ {
player.getClass().getNpcStats(player).getFactionRanks()[factionID] = player.getClass().getNpcStats(player).raiseRank(factionID);
std::min(player.getClass().getNpcStats(player).getFactionRanks()[factionID] +1,
9);
} }
} }
} }
@ -624,11 +619,7 @@ namespace MWScript
if(factionID != "") if(factionID != "")
{ {
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) != player.getClass().getNpcStats(player).getFactionRanks().end()) player.getClass().getNpcStats(player).lowerRank(factionID);
{
player.getClass().getNpcStats(player).getFactionRanks()[factionID] =
std::max(0, player.getClass().getNpcStats(player).getFactionRanks()[factionID]-1);
}
} }
} }
}; };
@ -668,7 +659,7 @@ namespace MWScript
{ {
if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) != player.getClass().getNpcStats(player).getFactionRanks().end()) if(player.getClass().getNpcStats(player).getFactionRanks().find(factionID) != player.getClass().getNpcStats(player).getFactionRanks().end())
{ {
runtime.push(player.getClass().getNpcStats(player).getFactionRanks()[factionID]); runtime.push(player.getClass().getNpcStats(player).getFactionRanks().at(factionID));
} }
else else
{ {
@ -1036,8 +1027,7 @@ namespace MWScript
if (ptr == player) if (ptr == player)
return; return;
std::map<std::string, int>& ranks = ptr.getClass().getNpcStats(ptr).getFactionRanks (); ptr.getClass().getNpcStats(ptr).raiseRank(factionID);
ranks[factionID] = std::min(9, ranks[factionID]+1);
} }
}; };
@ -1063,8 +1053,7 @@ namespace MWScript
if (ptr == player) if (ptr == player)
return; return;
std::map<std::string, int>& ranks = ptr.getClass().getNpcStats(ptr).getFactionRanks (); ptr.getClass().getNpcStats(ptr).lowerRank(factionID);
ranks[factionID] = std::max(0, ranks[factionID]-1);
} }
}; };

@ -5,6 +5,23 @@
#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/mechanicsmanager.hpp"
#include "player.hpp" #include "player.hpp"
namespace
{
void getFollowers (const MWWorld::Ptr& actor, std::set<MWWorld::Ptr>& out)
{
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
{
if (out.insert(*it).second)
{
getFollowers(*it, out);
}
}
}
}
namespace MWWorld namespace MWWorld
{ {
ActionTeleport::ActionTeleport (const std::string& cellName, ActionTeleport::ActionTeleport (const std::string& cellName,
@ -16,8 +33,9 @@ namespace MWWorld
void ActionTeleport::executeImp (const Ptr& actor) void ActionTeleport::executeImp (const Ptr& actor)
{ {
//find any NPC that is following the actor and teleport him too //find any NPC that is following the actor and teleport him too
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor); std::set<MWWorld::Ptr> followers;
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it) getFollowers(actor, followers);
for(std::set<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
{ {
teleport(*it); teleport(*it);
} }

@ -420,4 +420,13 @@ namespace MWWorld
{ {
throw std::runtime_error("this is not a door"); throw std::runtime_error("this is not a door");
} }
float Class::getNormalizedEncumbrance(const Ptr &ptr) const
{
float capacity = getCapacity(ptr);
if (capacity == 0)
return 1.f;
return getEncumbrance(ptr) / capacity;
}
} }

@ -223,6 +223,9 @@ namespace MWWorld
/// effects). Throws an exception, if the object can't hold other objects. /// effects). Throws an exception, if the object can't hold other objects.
/// (default implementation: throws an exception) /// (default implementation: throws an exception)
virtual float getNormalizedEncumbrance (const MWWorld::Ptr& ptr) const;
///< Returns encumbrance re-scaled to capacity
virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id, virtual bool apply (const MWWorld::Ptr& ptr, const std::string& id,
const MWWorld::Ptr& actor) const; const MWWorld::Ptr& actor) const;
///< Apply \a id on \a ptr. ///< Apply \a id on \a ptr.

@ -68,6 +68,7 @@ MWWorld::InventoryStore::InventoryStore()
, mUpdatesEnabled (true) , mUpdatesEnabled (true)
, mFirstAutoEquip(true) , mFirstAutoEquip(true)
, mListener(NULL) , mListener(NULL)
, mRechargingItemsUpToDate(false)
{ {
initSlots (mSlots); initSlots (mSlots);
} }
@ -80,6 +81,7 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
, mListener(store.mListener) , mListener(store.mListener)
, mUpdatesEnabled(store.mUpdatesEnabled) , mUpdatesEnabled(store.mUpdatesEnabled)
, mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes) , mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes)
, mRechargingItemsUpToDate(false)
{ {
copySlots (store); copySlots (store);
} }
@ -90,6 +92,7 @@ MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStor
mMagicEffects = store.mMagicEffects; mMagicEffects = store.mMagicEffects;
mFirstAutoEquip = store.mFirstAutoEquip; mFirstAutoEquip = store.mFirstAutoEquip;
mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes; mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes;
mRechargingItemsUpToDate = false;
ContainerStore::operator= (store); ContainerStore::operator= (store);
mSlots.clear(); mSlots.clear();
copySlots (store); copySlots (store);
@ -110,8 +113,6 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr,
autoEquip(actorPtr); autoEquip(actorPtr);
} }
updateRechargingItems();
return retVal; return retVal;
} }
@ -485,8 +486,6 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
mSelectedEnchantItem = end(); mSelectedEnchantItem = end();
} }
updateRechargingItems();
return retCount; return retCount;
} }
@ -606,6 +605,11 @@ void MWWorld::InventoryStore::updateRechargingItems()
void MWWorld::InventoryStore::rechargeItems(float duration) void MWWorld::InventoryStore::rechargeItems(float duration)
{ {
if (!mRechargingItemsUpToDate)
{
updateRechargingItems();
mRechargingItemsUpToDate = true;
}
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it) for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
{ {
if (it->first->getCellRef().getEnchantmentCharge() == -1 if (it->first->getCellRef().getEnchantmentCharge() == -1

@ -102,6 +102,8 @@ namespace MWWorld
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems; typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
TRechargingItems mRechargingItems; TRechargingItems mRechargingItems;
bool mRechargingItemsUpToDate;
void copySlots (const InventoryStore& store); void copySlots (const InventoryStore& store);
void initSlots (TSlots& slots_); void initSlots (TSlots& slots_);

@ -278,8 +278,10 @@ namespace MWWorld
if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr)) if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr))
return position; return position;
/* Anything to collide with? */
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle()); OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
// Reset per-frame data
physicActor->setWalkingOnWater(false);
/* Anything to collide with? */
if(!physicActor || !physicActor->getCollisionMode()) if(!physicActor || !physicActor->getCollisionMode())
{ {
return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
@ -307,9 +309,6 @@ namespace MWWorld
*/ */
OEngine::Physic::ActorTracer tracer; OEngine::Physic::ActorTracer tracer;
bool isOnGround = physicActor->getOnGround();
if (movement.z > 0.f)
isOnGround = false;
Ogre::Vector3 inertia(0.0f); Ogre::Vector3 inertia(0.0f);
Ogre::Vector3 velocity; Ogre::Vector3 velocity;
@ -426,8 +425,6 @@ namespace MWWorld
if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr)) if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr))
&& newPosition.z > (waterlevel - halfExtents.z * 0.5)) && newPosition.z > (waterlevel - halfExtents.z * 0.5))
newPosition = oldPosition; newPosition = oldPosition;
else // Only on the ground if there's gravity
isOnGround = !(newPosition.z < waterlevel || isFlying);
} }
else else
{ {
@ -444,10 +441,11 @@ namespace MWWorld
} }
} }
if (!(inertia.z > 0.f) && !(newPosition.z < waterlevel || isFlying)) bool isOnGround = false;
if (!(inertia.z > 0.f) && !(newPosition.z < waterlevel))
{ {
Ogre::Vector3 from = newPosition; Ogre::Vector3 from = newPosition;
Ogre::Vector3 to = newPosition - (isOnGround ? Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ?
Ogre::Vector3(0,0,sStepSize+2.f) : Ogre::Vector3(0,0,2.f)); Ogre::Vector3(0,0,sStepSize+2.f) : Ogre::Vector3(0,0,2.f));
tracer.doTrace(colobj, from, to, engine); tracer.doTrace(colobj, from, to, engine);
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope) if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
@ -457,8 +455,11 @@ namespace MWWorld
{ {
standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName; standingCollisionTracker[ptr.getRefData().getHandle()] = body->mName;
} }
if (standingOn->getBroadphaseHandle()->m_collisionFilterGroup == OEngine::Physic::CollisionType_Water)
physicActor->setWalkingOnWater(true);
newPosition.z = tracer.mEndPos.z + 1.0f; if (!isFlying)
newPosition.z = tracer.mEndPos.z + 1.0f;
isOnGround = true; isOnGround = true;
} }
@ -485,7 +486,7 @@ namespace MWWorld
PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) : PhysicsSystem::PhysicsSystem(OEngine::Render::OgreRenderer &_rend) :
mRender(_rend), mEngine(0), mTimeAccum(0.0f) mRender(_rend), mEngine(0), mTimeAccum(0.0f), mWaterEnabled(false), mWaterHeight(0)
{ {
// Create physics. shapeLoader is deleted by the physic engine // Create physics. shapeLoader is deleted by the physic engine
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
@ -494,6 +495,8 @@ namespace MWWorld
PhysicsSystem::~PhysicsSystem() PhysicsSystem::~PhysicsSystem()
{ {
if (mWaterCollisionObject.get())
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
delete mEngine; delete mEngine;
} }
@ -661,9 +664,9 @@ namespace MWWorld
Ogre::SceneNode* node = ptr.getRefData().getBaseNode(); Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
handleToMesh[node->getName()] = mesh; handleToMesh[node->getName()] = mesh;
mEngine->createAndAdjustRigidBody( mEngine->createAndAdjustRigidBody(
mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, false, placeable); mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, false, placeable);
mEngine->createAndAdjustRigidBody( mEngine->createAndAdjustRigidBody(
mesh, node->getName(), node->getScale().x, node->getPosition(), node->getOrientation(), 0, 0, true, placeable); mesh, node->getName(), ptr.getCellRef().getScale(), node->getPosition(), node->getOrientation(), 0, 0, true, placeable);
} }
void PhysicsSystem::addActor (const Ptr& ptr) void PhysicsSystem::addActor (const Ptr& ptr)
@ -855,14 +858,10 @@ namespace MWWorld
Ogre::Vector3(iter->first.getRefData().getPosition().pos))) Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
waterCollision = true; waterCollision = true;
btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel); OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle());
btCollisionObject object; if (!physicActor) // actor was already removed from the scene
object.setCollisionShape(&planeShape); continue;
physicActor->setCanWaterWalk(waterCollision);
// TODO: this seems to have a slight performance impact
if (waterCollision)
mEngine->mDynamicsWorld->addCollisionObject(&object,
0xff, OEngine::Physic::CollisionType_Actor);
// 100 points of slowfall reduce gravity by 90% (this is just a guess) // 100 points of slowfall reduce gravity by 90% (this is just a guess)
float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).getMagnitude() / 100.f) * 0.9f), 0.9f); float slowFall = 1-std::min(std::max(0.f, (effects.get(ESM::MagicEffect::SlowFall).getMagnitude() / 100.f) * 0.9f), 0.9f);
@ -871,9 +870,6 @@ namespace MWWorld
world->isFlying(iter->first), world->isFlying(iter->first),
waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions); waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions);
if (waterCollision)
mEngine->mDynamicsWorld->removeCollisionObject(&object);
float heightDiff = newpos.z - oldHeight; float heightDiff = newpos.z - oldHeight;
if (heightDiff < 0) if (heightDiff < 0)
@ -949,4 +945,48 @@ namespace MWWorld
} }
} }
void PhysicsSystem::disableWater()
{
if (mWaterEnabled)
{
mWaterEnabled = false;
updateWater();
}
}
void PhysicsSystem::enableWater(float height)
{
if (!mWaterEnabled || mWaterHeight != height)
{
mWaterEnabled = true;
mWaterHeight = height;
updateWater();
}
}
void PhysicsSystem::setWaterHeight(float height)
{
if (mWaterHeight != height)
{
mWaterHeight = height;
updateWater();
}
}
void PhysicsSystem::updateWater()
{
if (mWaterCollisionObject.get())
{
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
}
if (!mWaterEnabled)
return;
mWaterCollisionObject.reset(new btCollisionObject());
mWaterCollisionShape.reset(new btStaticPlaneShape(btVector3(0,0,1), mWaterHeight));
mWaterCollisionObject->setCollisionShape(mWaterCollisionShape.get());
mEngine->mDynamicsWorld->addCollisionObject(mWaterCollisionObject.get(), OEngine::Physic::CollisionType_Water,
OEngine::Physic::CollisionType_Actor);
}
} }

@ -1,6 +1,8 @@
#ifndef GAME_MWWORLD_PHYSICSSYSTEM_H #ifndef GAME_MWWORLD_PHYSICSSYSTEM_H
#define GAME_MWWORLD_PHYSICSSYSTEM_H #define GAME_MWWORLD_PHYSICSSYSTEM_H
#include <memory>
#include <OgreVector3.h> #include <OgreVector3.h>
#include <btBulletCollisionCommon.h> #include <btBulletCollisionCommon.h>
@ -32,6 +34,10 @@ namespace MWWorld
PhysicsSystem (OEngine::Render::OgreRenderer &_rend); PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
~PhysicsSystem (); ~PhysicsSystem ();
void enableWater(float height);
void setWaterHeight(float height);
void disableWater();
void addObject (const MWWorld::Ptr& ptr, bool placeable=false); void addObject (const MWWorld::Ptr& ptr, bool placeable=false);
void addActor (const MWWorld::Ptr& ptr); void addActor (const MWWorld::Ptr& ptr);
@ -108,6 +114,8 @@ namespace MWWorld
private: private:
void updateWater();
OEngine::Render::OgreRenderer &mRender; OEngine::Render::OgreRenderer &mRender;
OEngine::Physic::PhysicEngine* mEngine; OEngine::Physic::PhysicEngine* mEngine;
std::map<std::string, std::string> handleToMesh; std::map<std::string, std::string> handleToMesh;
@ -124,6 +132,12 @@ namespace MWWorld
float mTimeAccum; float mTimeAccum;
float mWaterHeight;
float mWaterEnabled;
std::auto_ptr<btCollisionObject> mWaterCollisionObject;
std::auto_ptr<btCollisionShape> mWaterCollisionShape;
PhysicsSystem (const PhysicsSystem&); PhysicsSystem (const PhysicsSystem&);
PhysicsSystem& operator= (const PhysicsSystem&); PhysicsSystem& operator= (const PhysicsSystem&);
}; };

@ -153,7 +153,8 @@ namespace MWWorld
Ogre::Vector3 pos(it->mNode->getPosition()); Ogre::Vector3 pos(it->mNode->getPosition());
Ogre::Vector3 newPos = pos + direction * duration * speed; Ogre::Vector3 newPos = pos + direction * duration * speed;
it->mSound->setPosition(newPos); if (it->mSound.get())
it->mSound->setPosition(newPos);
it->mNode->setPosition(newPos); it->mNode->setPosition(newPos);
@ -163,7 +164,8 @@ namespace MWWorld
// TODO: use a proper btRigidBody / btGhostObject? // TODO: use a proper btRigidBody / btGhostObject?
btVector3 from(pos.x, pos.y, pos.z); btVector3 from(pos.x, pos.y, pos.z);
btVector3 to(newPos.x, newPos.y, newPos.z); btVector3 to(newPos.x, newPos.y, newPos.z);
std::vector<std::pair<float, std::string> > collisions = mPhysEngine.rayTest2(from, to);
std::vector<std::pair<float, std::string> > collisions = mPhysEngine.rayTest2(from, to, OEngine::Physic::CollisionType_Projectile);
bool hit=false; bool hit=false;
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt) for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt)
@ -239,7 +241,7 @@ namespace MWWorld
// TODO: use a proper btRigidBody / btGhostObject? // TODO: use a proper btRigidBody / btGhostObject?
btVector3 from(pos.x, pos.y, pos.z); btVector3 from(pos.x, pos.y, pos.z);
btVector3 to(newPos.x, newPos.y, newPos.z); btVector3 to(newPos.x, newPos.y, newPos.z);
std::vector<std::pair<float, std::string> > collisions = mPhysEngine.rayTest2(from, to); std::vector<std::pair<float, std::string> > collisions = mPhysEngine.rayTest2(from, to, OEngine::Physic::CollisionType_Projectile);
bool hit=false; bool hit=false;
for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt) for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt)
@ -408,6 +410,7 @@ namespace MWWorld
MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager(); MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f, state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f,
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
state.mSoundId = esm.mSound;
mMagicBolts.push_back(state); mMagicBolts.push_back(state);
return true; return true;

@ -83,7 +83,12 @@ namespace
ptr.getClass().insertObject (ptr, mPhysics); ptr.getClass().insertObject (ptr, mPhysics);
updateObjectLocalRotation(ptr, mPhysics, mRendering); updateObjectLocalRotation(ptr, mPhysics, mRendering);
MWBase::Environment::get().getWorld()->scaleObject (ptr, ptr.getCellRef().getScale()); if (ptr.getRefData().getBaseNode())
{
float scale = ptr.getCellRef().getScale();
ptr.getClass().adjustScale(ptr, scale);
mRendering.scaleObject(ptr, Ogre::Vector3(scale));
}
ptr.getClass().adjustPosition (ptr, false); ptr.getClass().adjustPosition (ptr, false);
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -233,6 +238,15 @@ namespace MWWorld
insertCell (*cell, true, loadingListener); insertCell (*cell, true, loadingListener);
mRendering.cellAdded (cell); mRendering.cellAdded (cell);
bool waterEnabled = cell->getCell()->hasWater();
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
{
mPhysics->enableWater(cell->getWaterLevel());
mRendering.setWaterHeight(cell->getWaterLevel());
}
else
mPhysics->disableWater();
mRendering.configureAmbient(*cell); mRendering.configureAmbient(*cell);
} }

@ -1660,6 +1660,7 @@ namespace MWWorld
void World::setWaterHeight(const float height) void World::setWaterHeight(const float height)
{ {
mPhysics->setWaterHeight(height);
mRendering->setWaterHeight(height); mRendering->setWaterHeight(height);
} }
@ -1994,7 +1995,7 @@ namespace MWWorld
Ogre::Vector3 playerPos(refdata.getPosition().pos); Ogre::Vector3 playerPos(refdata.getPosition().pos);
const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle());
if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos)) if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos) || isWalkingOnWater(player))
return 2; return 2;
if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) || if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) ||
player.getClass().getNpcStats(player).isWerewolf()) player.getClass().getNpcStats(player).isWerewolf())
@ -3073,4 +3074,12 @@ namespace MWWorld
cellstore->forEach(functor); cellstore->forEach(functor);
} }
} }
bool World::isWalkingOnWater(const Ptr &actor)
{
OEngine::Physic::PhysicActor* physicActor = mPhysEngine->getCharacter(actor.getRefData().getHandle());
if (physicActor && physicActor->isWalkingOnWater())
return true;
return false;
}
} }

@ -615,6 +615,8 @@ namespace MWWorld
/// Resets all actors in the current active cells to their original location within that cell. /// Resets all actors in the current active cells to their original location within that cell.
virtual void resetActors(); virtual void resetActors();
virtual bool isWalkingOnWater (const MWWorld::Ptr& actor);
}; };
} }

@ -74,6 +74,8 @@ namespace Physic
, mExternalCollisionMode(true) , mExternalCollisionMode(true)
, mForce(0.0f) , mForce(0.0f)
, mScale(scale) , mScale(scale)
, mWalkingOnWater(false)
, mCanWaterWalk(false)
{ {
if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation)) if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation))
{ {
@ -103,8 +105,7 @@ namespace Physic
setPosition(position); setPosition(position);
setRotation(rotation); setRotation(rotation);
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, updateCollisionMask();
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap);
} }
PhysicActor::~PhysicActor() PhysicActor::~PhysicActor()
@ -123,10 +124,22 @@ namespace Physic
void PhysicActor::enableCollisionBody(bool collision) void PhysicActor::enableCollisionBody(bool collision)
{ {
assert(mBody); if (mExternalCollisionMode != collision)
if(collision && !mExternalCollisionMode) enableCollisionBody(); {
if(!collision && mExternalCollisionMode) disableCollisionBody(); mExternalCollisionMode = collision;
mExternalCollisionMode = collision; updateCollisionMask();
}
}
void PhysicActor::updateCollisionMask()
{
mEngine->mDynamicsWorld->removeRigidBody(mBody);
int collisionMask = CollisionType_World | CollisionType_HeightMap;
if (mExternalCollisionMode)
collisionMask |= CollisionType_Actor | CollisionType_Projectile;
if (mCanWaterWalk)
collisionMask |= CollisionType_Water;
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, collisionMask);
} }
const Ogre::Vector3& PhysicActor::getPosition() const const Ogre::Vector3& PhysicActor::getPosition() const
@ -178,18 +191,23 @@ namespace Physic
mOnGround = grounded; mOnGround = grounded;
} }
void PhysicActor::disableCollisionBody() bool PhysicActor::isWalkingOnWater() const
{ {
mEngine->mDynamicsWorld->removeRigidBody(mBody); return mWalkingOnWater;
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
CollisionType_World|CollisionType_HeightMap);
} }
void PhysicActor::enableCollisionBody() void PhysicActor::setWalkingOnWater(bool walkingOnWater)
{ {
mEngine->mDynamicsWorld->removeRigidBody(mBody); mWalkingOnWater = walkingOnWater;
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor, }
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap);
void PhysicActor::setCanWaterWalk(bool waterWalk)
{
if (waterWalk != mCanWaterWalk)
{
mCanWaterWalk = waterWalk;
updateCollisionMask();
}
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -381,7 +399,7 @@ namespace Physic
mHeightFieldMap [name] = hf; mHeightFieldMap [name] = hf;
mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap, mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap,
CollisionType_Actor|CollisionType_Raycasting); CollisionType_Actor|CollisionType_Raycasting|CollisionType_Projectile);
} }
void PhysicEngine::removeHeightField(int x, int y) void PhysicEngine::removeHeightField(int x, int y)
@ -494,7 +512,7 @@ namespace Physic
{ {
assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end()); assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end());
mRaycastingObjectMap[name] = body; mRaycastingObjectMap[name] = body;
mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting); mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_Projectile);
} }
return body; return body;
@ -800,10 +818,10 @@ namespace Physic
return std::make_pair(false, 1); return std::make_pair(false, 1);
} }
std::vector< std::pair<float, std::string> > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to) std::vector< std::pair<float, std::string> > PhysicEngine::rayTest2(const btVector3& from, const btVector3& to, int filterGroup)
{ {
MyRayResultCallback resultCallback1; MyRayResultCallback resultCallback1;
resultCallback1.m_collisionFilterGroup = 0xff; resultCallback1.m_collisionFilterGroup = filterGroup;
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor|CollisionType_HeightMap; resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor|CollisionType_HeightMap;
mDynamicsWorld->rayTest(from, to, resultCallback1); mDynamicsWorld->rayTest(from, to, resultCallback1);
std::vector< std::pair<float, const btCollisionObject*> > results = resultCallback1.results; std::vector< std::pair<float, const btCollisionObject*> > results = resultCallback1.results;

@ -46,7 +46,9 @@ namespace Physic
CollisionType_World = 1<<0, //<Collide with world objects CollisionType_World = 1<<0, //<Collide with world objects
CollisionType_Actor = 1<<1, //<Collide sith actors CollisionType_Actor = 1<<1, //<Collide sith actors
CollisionType_HeightMap = 1<<2, //<collide with heightmap CollisionType_HeightMap = 1<<2, //<collide with heightmap
CollisionType_Raycasting = 1<<3 //Still used? CollisionType_Raycasting = 1<<3,
CollisionType_Projectile = 1<<4,
CollisionType_Water = 1<<5
}; };
/** /**
@ -130,9 +132,20 @@ namespace Physic
return mBody; return mBody;
} }
/// Sets whether this actor should be able to collide with the water surface
void setCanWaterWalk(bool waterWalk);
/// Sets whether this actor has been walking on the water surface in the last frame
void setWalkingOnWater(bool walkingOnWater);
bool isWalkingOnWater() const;
private: private:
void disableCollisionBody(); /// Removes then re-adds the collision body to the dynamics world
void enableCollisionBody(); void updateCollisionMask();
bool mCanWaterWalk;
bool mWalkingOnWater;
boost::shared_ptr<btCollisionShape> mShape; boost::shared_ptr<btCollisionShape> mShape;
@ -288,7 +301,7 @@ namespace Physic
/** /**
* Return all objects hit by a ray. * Return all objects hit by a ray.
*/ */
std::vector< std::pair<float, std::string> > rayTest2(const btVector3 &from, const btVector3 &to); std::vector< std::pair<float, std::string> > rayTest2(const btVector3 &from, const btVector3 &to, int filterGroup=0xff);
std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to); std::pair<bool, float> sphereCast (float radius, btVector3& from, btVector3& to);
///< @return (hit, relative distance) ///< @return (hit, relative distance)

Loading…
Cancel
Save