mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 15:35:23 +00:00
Merge branch 'master' of github.com:OpenMW/openmw
This commit is contained in:
commit
ff74d54e98
31
.travis.yml
31
.travis.yml
@ -1,37 +1,26 @@
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /openmw-.*$/
|
||||
before_install:
|
||||
- pwd
|
||||
- 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
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
|
||||
before_script:
|
||||
- cd -
|
||||
- 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
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_script.linux.sh; fi
|
||||
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
|
||||
script:
|
||||
- cd ./build
|
||||
- make -j4
|
||||
after_script:
|
||||
- ./openmw_test_suite
|
||||
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
|
||||
notifications:
|
||||
recipients:
|
||||
- lgromanowski+travis.ci@gmail.com
|
||||
- corrmage+travis-ci@gmail.com
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
18
CI/before_install.linux.sh
Executable file
18
CI/before_install.linux.sh
Executable file
@ -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
|
9
CI/before_install.osx.sh
Executable file
9
CI/before_install.osx.sh
Executable file
@ -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
|
5
CI/before_script.linux.sh
Executable file
5
CI/before_script.linux.sh
Executable file
@ -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
|
5
CI/before_script.osx.sh
Executable file
5
CI/before_script.osx.sh
Executable file
@ -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.
|
||||
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 fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::DynamicStat<float> fatigue = stats.getFatigue();
|
||||
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
|
||||
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
||||
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||
if (!weapon.isEmpty())
|
||||
fatigueLoss += weapon.getClass().getWeight(weapon) * stats.getAttackStrength() * fWeaponFatigueMult;
|
||||
@ -537,7 +537,7 @@ namespace MWClass
|
||||
const MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
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);
|
||||
|
||||
@ -738,7 +738,7 @@ namespace MWClass
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
if(world->isUnderwater(ptr.getCell(), pos))
|
||||
if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
||||
return 2;
|
||||
if(world->isOnGround(ptr))
|
||||
return 0;
|
||||
@ -748,7 +748,7 @@ namespace MWClass
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
if(world->isUnderwater(ptr.getCell(), pos))
|
||||
if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
||||
return 3;
|
||||
if(world->isOnGround(ptr))
|
||||
return 1;
|
||||
|
@ -302,11 +302,11 @@ namespace MWClass
|
||||
Misc::StringUtils::toLower(faction);
|
||||
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
|
||||
{
|
||||
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 fWeaponFatigueMult = store.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::DynamicStat<float> fatigue = getCreatureStats(ptr).getFatigue();
|
||||
const float normalizedEncumbrance = getEncumbrance(ptr) / getCapacity(ptr);
|
||||
const float normalizedEncumbrance = getNormalizedEncumbrance(ptr);
|
||||
float fatigueLoss = fFatigueAttackBase + normalizedEncumbrance * fFatigueAttackMult;
|
||||
if (!weapon.isEmpty())
|
||||
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 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 running = ptr.getClass().getCreatureStats(ptr).getStance(MWMechanics::CreatureStats::Stance_Run);
|
||||
@ -930,7 +930,7 @@ namespace MWClass
|
||||
gmst.fAthleticsRunBonus->getFloat() + gmst.fBaseRunMultiplier->getFloat());
|
||||
|
||||
float moveSpeed;
|
||||
if(normalizedEncumbrance >= 1.0f)
|
||||
if(getEncumbrance(ptr) > getCapacity(ptr))
|
||||
moveSpeed = 0.0f;
|
||||
else if(mageffects.get(ESM::MagicEffect::Levitate).getMagnitude() > 0 &&
|
||||
world->isLevitationEnabled())
|
||||
@ -1225,7 +1225,7 @@ namespace MWClass
|
||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
if(world->isSwimming(ptr))
|
||||
return "Swim Left";
|
||||
if(world->isUnderwater(ptr.getCell(), pos))
|
||||
if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
||||
return "FootWaterLeft";
|
||||
if(world->isOnGround(ptr))
|
||||
{
|
||||
@ -1252,7 +1252,7 @@ namespace MWClass
|
||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
if(world->isSwimming(ptr))
|
||||
return "Swim Right";
|
||||
if(world->isUnderwater(ptr.getCell(), pos))
|
||||
if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
||||
return "FootWaterRight";
|
||||
if(world->isOnGround(ptr))
|
||||
{
|
||||
@ -1277,7 +1277,7 @@ namespace MWClass
|
||||
{
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
|
||||
if(world->isUnderwater(ptr.getCell(), pos))
|
||||
if(world->isUnderwater(ptr.getCell(), pos) || world->isWalkingOnWater(ptr))
|
||||
return "DefaultLandWater";
|
||||
if(world->isOnGround(ptr))
|
||||
return "Body Fall Medium";
|
||||
|
@ -68,7 +68,7 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
||||
return false;
|
||||
|
||||
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())
|
||||
return false;
|
||||
@ -112,7 +112,7 @@ bool MWDialogue::Filter::testPlayer (const ESM::DialInfo& info) const
|
||||
if (!info.mPcFaction.empty())
|
||||
{
|
||||
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())
|
||||
return false;
|
||||
@ -379,7 +379,7 @@ int MWDialogue::Filter::getSelectStructInteger (const SelectWrapper& select) con
|
||||
if (mActor.getClass().getNpcStats (mActor).getFactionRanks().empty())
|
||||
return 0;
|
||||
|
||||
std::pair<std::string, int> faction =
|
||||
const std::pair<std::string, int> faction =
|
||||
*mActor.getClass().getNpcStats (mActor).getFactionRanks().begin();
|
||||
|
||||
int rank = getFactionRank (player, faction.first);
|
||||
|
@ -333,7 +333,8 @@ namespace MWGui
|
||||
float e1 = 0.1f * sellerStats.getAttribute(ESM::Attribute::Luck).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 x = gmst.find("fBargainOfferMulti")->getFloat() * d + gmst.find("fBargainOfferBase")->getFloat();
|
||||
if (buying)
|
||||
|
@ -385,7 +385,7 @@ namespace MWInput
|
||||
{
|
||||
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||
mOverencumberedMessageDelay -= dt;
|
||||
if (player.getClass().getEncumbrance(player) >= player.getClass().getCapacity(player))
|
||||
if (player.getClass().getEncumbrance(player) > player.getClass().getCapacity(player))
|
||||
{
|
||||
mPlayer->setAutoMove (false);
|
||||
if (mOverencumberedMessageDelay <= 0)
|
||||
|
@ -445,9 +445,7 @@ namespace MWMechanics
|
||||
|
||||
int endurance = stats.getAttribute (ESM::Attribute::Endurance).getModified ();
|
||||
|
||||
float capacity = ptr.getClass().getCapacity(ptr);
|
||||
float encumbrance = ptr.getClass().getEncumbrance(ptr);
|
||||
float normalizedEncumbrance = (capacity == 0 ? 1 : encumbrance/capacity);
|
||||
float normalizedEncumbrance = ptr.getClass().getNormalizedEncumbrance(ptr);
|
||||
if (normalizedEncumbrance > 1)
|
||||
normalizedEncumbrance = 1;
|
||||
|
||||
@ -1447,6 +1445,8 @@ namespace MWMechanics
|
||||
continue;
|
||||
if (followTarget == actor)
|
||||
list.push_back(iter->first);
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if ((*it)->getTypeId() != MWMechanics::AiPackage::TypeIdCombat)
|
||||
break;
|
||||
|
@ -1428,7 +1428,9 @@ void CharacterController::update(float duration)
|
||||
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
|
||||
const float fatigueJumpBase = gmst.find("fFatigueJumpBase")->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;
|
||||
DynamicStat<float> fatigue = cls.getCreatureStats(mPtr).getFatigue();
|
||||
fatigue.setCurrent(fatigue.getCurrent() - fatigueDecrease);
|
||||
|
@ -124,7 +124,7 @@ namespace MWMechanics
|
||||
const float fFatigueBlockMult = gmst.find("fFatigueBlockMult")->getFloat();
|
||||
const float fWeaponFatigueBlockMult = gmst.find("fWeaponFatigueBlockMult")->getFloat();
|
||||
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);
|
||||
float fatigueLoss = fFatigueBlockBase + normalizedEncumbrance * fFatigueBlockMult;
|
||||
fatigueLoss += weapon.getClass().getWeight(weapon) * attackerStats.getAttackStrength() * fWeaponFatigueBlockMult;
|
||||
|
@ -69,9 +69,41 @@ const std::map<std::string, int>& MWMechanics::NpcStats::getFactionRanks() const
|
||||
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
|
||||
|
@ -70,7 +70,15 @@ namespace MWMechanics
|
||||
SkillValue& getSkill (int index);
|
||||
|
||||
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; }
|
||||
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 fFatigueSpellMult = store.get<ESM::GameSetting>().find("fFatigueSpellMult")->getFloat();
|
||||
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);
|
||||
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::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;
|
||||
sndMgr->playSound3D(mPtr, sound, volume, pitch, type);
|
||||
}
|
||||
|
@ -250,7 +250,6 @@ void RenderingManager::cellAdded (MWWorld::CellStore *store)
|
||||
mObjects->buildStaticGeometry (*store);
|
||||
sh::Factory::getInstance().unloadUnreferencedMaterials();
|
||||
mDebugging->cellAdded(store);
|
||||
waterAdded(store);
|
||||
}
|
||||
|
||||
void RenderingManager::addObject (const MWWorld::Ptr& ptr){
|
||||
@ -421,18 +420,12 @@ void RenderingManager::postRenderTargetUpdate(const RenderTargetEvent &evt)
|
||||
mOcclusionQuery->setActive(false);
|
||||
}
|
||||
|
||||
void RenderingManager::waterAdded (MWWorld::CellStore *store)
|
||||
void RenderingManager::setWaterEnabled(bool enable)
|
||||
{
|
||||
if (store->getCell()->mData.mFlags & ESM::Cell::HasWater)
|
||||
{
|
||||
mWater->changeCell (store->getCell());
|
||||
mWater->setActive(true);
|
||||
}
|
||||
else
|
||||
removeWater();
|
||||
mWater->setActive(enable);
|
||||
}
|
||||
|
||||
void RenderingManager::setWaterHeight(const float height)
|
||||
void RenderingManager::setWaterHeight(float height)
|
||||
{
|
||||
mWater->setHeight(height);
|
||||
}
|
||||
|
@ -100,7 +100,6 @@ public:
|
||||
/// \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.
|
||||
void cellAdded (MWWorld::CellStore *store);
|
||||
void waterAdded(MWWorld::CellStore *store);
|
||||
|
||||
/// Clear all savegame-specific data (i.e. fog of war textures)
|
||||
void clear();
|
||||
@ -121,7 +120,8 @@ public:
|
||||
/// Updates an object's rotation
|
||||
void rotateObject (const MWWorld::Ptr& ptr);
|
||||
|
||||
void setWaterHeight(const float height);
|
||||
void setWaterHeight(float height);
|
||||
void setWaterEnabled(bool enabled);
|
||||
bool toggleWater();
|
||||
bool toggleWorld();
|
||||
|
||||
|
@ -81,7 +81,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor)
|
||||
const float fWeaponFatigueMult = gmst.find("fWeaponFatigueMult")->getFloat();
|
||||
MWMechanics::CreatureStats& attackerStats = actor.getClass().getCreatureStats(actor);
|
||||
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;
|
||||
if (!weapon->isEmpty())
|
||||
fatigueLoss += weapon->getClass().getWeight(*weapon) * attackerStats.getAttackStrength() * fWeaponFatigueMult;
|
||||
|
@ -290,18 +290,15 @@ namespace MWScript
|
||||
const std::string &name = runtime.getStringLiteral (runtime[0].mInteger);
|
||||
runtime.pop();
|
||||
|
||||
int count = 0;
|
||||
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore (ptr);
|
||||
for (MWWorld::ContainerStoreIterator it = invStore.begin(MWWorld::ContainerStore::Type_Miscellaneous);
|
||||
it != invStore.end(); ++it)
|
||||
{
|
||||
|
||||
if (::Misc::StringUtils::ciEqual(it->getCellRef().getSoul(), name))
|
||||
{
|
||||
runtime.push(1);
|
||||
return;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
runtime.push(0);
|
||||
runtime.push(count);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -310,7 +310,7 @@ namespace MWScript
|
||||
|
||||
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();
|
||||
|
||||
MWBase::World *world = MWBase::Environment::get().getWorld();
|
||||
@ -348,7 +348,7 @@ namespace MWScript
|
||||
|
||||
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);
|
||||
int rank = -1;
|
||||
if (it != ranks.end())
|
||||
@ -375,7 +375,7 @@ namespace MWScript
|
||||
|
||||
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);
|
||||
int rank = -1;
|
||||
if (it != ranks.end())
|
||||
|
@ -548,10 +548,7 @@ namespace MWScript
|
||||
if(factionID != "")
|
||||
{
|
||||
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).getFactionRanks()[factionID] = 0;
|
||||
}
|
||||
player.getClass().getNpcStats(player).joinFaction(factionID);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -585,13 +582,11 @@ namespace MWScript
|
||||
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).getFactionRanks()[factionID] = 0;
|
||||
player.getClass().getNpcStats(player).joinFaction(factionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
player.getClass().getNpcStats(player).getFactionRanks()[factionID] =
|
||||
std::min(player.getClass().getNpcStats(player).getFactionRanks()[factionID] +1,
|
||||
9);
|
||||
player.getClass().getNpcStats(player).raiseRank(factionID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -624,11 +619,7 @@ namespace MWScript
|
||||
if(factionID != "")
|
||||
{
|
||||
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).getFactionRanks()[factionID] =
|
||||
std::max(0, player.getClass().getNpcStats(player).getFactionRanks()[factionID]-1);
|
||||
}
|
||||
player.getClass().getNpcStats(player).lowerRank(factionID);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -668,7 +659,7 @@ namespace MWScript
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -1036,8 +1027,7 @@ namespace MWScript
|
||||
if (ptr == player)
|
||||
return;
|
||||
|
||||
std::map<std::string, int>& ranks = ptr.getClass().getNpcStats(ptr).getFactionRanks ();
|
||||
ranks[factionID] = std::min(9, ranks[factionID]+1);
|
||||
ptr.getClass().getNpcStats(ptr).raiseRank(factionID);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1063,8 +1053,7 @@ namespace MWScript
|
||||
if (ptr == player)
|
||||
return;
|
||||
|
||||
std::map<std::string, int>& ranks = ptr.getClass().getNpcStats(ptr).getFactionRanks ();
|
||||
ranks[factionID] = std::max(0, ranks[factionID]-1);
|
||||
ptr.getClass().getNpcStats(ptr).lowerRank(factionID);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,6 +5,23 @@
|
||||
#include "../mwbase/mechanicsmanager.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
|
||||
{
|
||||
ActionTeleport::ActionTeleport (const std::string& cellName,
|
||||
@ -16,8 +33,9 @@ namespace MWWorld
|
||||
void ActionTeleport::executeImp (const Ptr& actor)
|
||||
{
|
||||
//find any NPC that is following the actor and teleport him too
|
||||
std::list<MWWorld::Ptr> followers = MWBase::Environment::get().getMechanicsManager()->getActorsFollowing(actor);
|
||||
for(std::list<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
std::set<MWWorld::Ptr> followers;
|
||||
getFollowers(actor, followers);
|
||||
for(std::set<MWWorld::Ptr>::iterator it = followers.begin();it != followers.end();++it)
|
||||
{
|
||||
teleport(*it);
|
||||
}
|
||||
|
@ -420,4 +420,13 @@ namespace MWWorld
|
||||
{
|
||||
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.
|
||||
/// (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,
|
||||
const MWWorld::Ptr& actor) const;
|
||||
///< Apply \a id on \a ptr.
|
||||
|
@ -68,6 +68,7 @@ MWWorld::InventoryStore::InventoryStore()
|
||||
, mUpdatesEnabled (true)
|
||||
, mFirstAutoEquip(true)
|
||||
, mListener(NULL)
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
initSlots (mSlots);
|
||||
}
|
||||
@ -80,6 +81,7 @@ MWWorld::InventoryStore::InventoryStore (const InventoryStore& store)
|
||||
, mListener(store.mListener)
|
||||
, mUpdatesEnabled(store.mUpdatesEnabled)
|
||||
, mPermanentMagicEffectMagnitudes(store.mPermanentMagicEffectMagnitudes)
|
||||
, mRechargingItemsUpToDate(false)
|
||||
{
|
||||
copySlots (store);
|
||||
}
|
||||
@ -90,6 +92,7 @@ MWWorld::InventoryStore& MWWorld::InventoryStore::operator= (const InventoryStor
|
||||
mMagicEffects = store.mMagicEffects;
|
||||
mFirstAutoEquip = store.mFirstAutoEquip;
|
||||
mPermanentMagicEffectMagnitudes = store.mPermanentMagicEffectMagnitudes;
|
||||
mRechargingItemsUpToDate = false;
|
||||
ContainerStore::operator= (store);
|
||||
mSlots.clear();
|
||||
copySlots (store);
|
||||
@ -110,8 +113,6 @@ MWWorld::ContainerStoreIterator MWWorld::InventoryStore::add(const Ptr& itemPtr,
|
||||
autoEquip(actorPtr);
|
||||
}
|
||||
|
||||
updateRechargingItems();
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@ -485,8 +486,6 @@ int MWWorld::InventoryStore::remove(const Ptr& item, int count, const Ptr& actor
|
||||
mSelectedEnchantItem = end();
|
||||
}
|
||||
|
||||
updateRechargingItems();
|
||||
|
||||
return retCount;
|
||||
}
|
||||
|
||||
@ -606,6 +605,11 @@ void MWWorld::InventoryStore::updateRechargingItems()
|
||||
|
||||
void MWWorld::InventoryStore::rechargeItems(float duration)
|
||||
{
|
||||
if (!mRechargingItemsUpToDate)
|
||||
{
|
||||
updateRechargingItems();
|
||||
mRechargingItemsUpToDate = true;
|
||||
}
|
||||
for (TRechargingItems::iterator it = mRechargingItems.begin(); it != mRechargingItems.end(); ++it)
|
||||
{
|
||||
if (it->first->getCellRef().getEnchantmentCharge() == -1
|
||||
|
@ -102,6 +102,8 @@ namespace MWWorld
|
||||
typedef std::vector<std::pair<ContainerStoreIterator, float> > TRechargingItems;
|
||||
TRechargingItems mRechargingItems;
|
||||
|
||||
bool mRechargingItemsUpToDate;
|
||||
|
||||
void copySlots (const InventoryStore& store);
|
||||
|
||||
void initSlots (TSlots& slots_);
|
||||
|
@ -278,8 +278,10 @@ namespace MWWorld
|
||||
if (!ptr.getClass().canWalk(ptr) && !ptr.getClass().canFly(ptr) && !ptr.getClass().canSwim(ptr))
|
||||
return position;
|
||||
|
||||
/* Anything to collide with? */
|
||||
OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
|
||||
// Reset per-frame data
|
||||
physicActor->setWalkingOnWater(false);
|
||||
/* Anything to collide with? */
|
||||
if(!physicActor || !physicActor->getCollisionMode())
|
||||
{
|
||||
return position + (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
|
||||
@ -307,9 +309,6 @@ namespace MWWorld
|
||||
*/
|
||||
|
||||
OEngine::Physic::ActorTracer tracer;
|
||||
bool isOnGround = physicActor->getOnGround();
|
||||
if (movement.z > 0.f)
|
||||
isOnGround = false;
|
||||
Ogre::Vector3 inertia(0.0f);
|
||||
Ogre::Vector3 velocity;
|
||||
|
||||
@ -426,8 +425,6 @@ namespace MWWorld
|
||||
if((ptr.getClass().canSwim(ptr) && !ptr.getClass().canWalk(ptr))
|
||||
&& newPosition.z > (waterlevel - halfExtents.z * 0.5))
|
||||
newPosition = oldPosition;
|
||||
else // Only on the ground if there's gravity
|
||||
isOnGround = !(newPosition.z < waterlevel || isFlying);
|
||||
}
|
||||
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 to = newPosition - (isOnGround ?
|
||||
Ogre::Vector3 to = newPosition - (physicActor->getOnGround() ?
|
||||
Ogre::Vector3(0,0,sStepSize+2.f) : Ogre::Vector3(0,0,2.f));
|
||||
tracer.doTrace(colobj, from, to, engine);
|
||||
if(tracer.mFraction < 1.0f && getSlope(tracer.mPlaneNormal) <= sMaxSlope)
|
||||
@ -457,8 +455,11 @@ namespace MWWorld
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -485,7 +486,7 @@ namespace MWWorld
|
||||
|
||||
|
||||
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
|
||||
NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader();
|
||||
@ -494,6 +495,8 @@ namespace MWWorld
|
||||
|
||||
PhysicsSystem::~PhysicsSystem()
|
||||
{
|
||||
if (mWaterCollisionObject.get())
|
||||
mEngine->mDynamicsWorld->removeCollisionObject(mWaterCollisionObject.get());
|
||||
delete mEngine;
|
||||
}
|
||||
|
||||
@ -661,9 +664,9 @@ namespace MWWorld
|
||||
Ogre::SceneNode* node = ptr.getRefData().getBaseNode();
|
||||
handleToMesh[node->getName()] = mesh;
|
||||
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(
|
||||
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)
|
||||
@ -855,14 +858,10 @@ namespace MWWorld
|
||||
Ogre::Vector3(iter->first.getRefData().getPosition().pos)))
|
||||
waterCollision = true;
|
||||
|
||||
btStaticPlaneShape planeShape(btVector3(0,0,1), waterlevel);
|
||||
btCollisionObject object;
|
||||
object.setCollisionShape(&planeShape);
|
||||
|
||||
// TODO: this seems to have a slight performance impact
|
||||
if (waterCollision)
|
||||
mEngine->mDynamicsWorld->addCollisionObject(&object,
|
||||
0xff, OEngine::Physic::CollisionType_Actor);
|
||||
OEngine::Physic::PhysicActor *physicActor = mEngine->getCharacter(iter->first.getRefData().getHandle());
|
||||
if (!physicActor) // actor was already removed from the scene
|
||||
continue;
|
||||
physicActor->setCanWaterWalk(waterCollision);
|
||||
|
||||
// 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);
|
||||
@ -871,9 +870,6 @@ namespace MWWorld
|
||||
world->isFlying(iter->first),
|
||||
waterlevel, slowFall, mEngine, mCollisions, mStandingCollisions);
|
||||
|
||||
if (waterCollision)
|
||||
mEngine->mDynamicsWorld->removeCollisionObject(&object);
|
||||
|
||||
float heightDiff = newpos.z - oldHeight;
|
||||
|
||||
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
|
||||
#define GAME_MWWORLD_PHYSICSSYSTEM_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <OgreVector3.h>
|
||||
|
||||
#include <btBulletCollisionCommon.h>
|
||||
@ -32,6 +34,10 @@ namespace MWWorld
|
||||
PhysicsSystem (OEngine::Render::OgreRenderer &_rend);
|
||||
~PhysicsSystem ();
|
||||
|
||||
void enableWater(float height);
|
||||
void setWaterHeight(float height);
|
||||
void disableWater();
|
||||
|
||||
void addObject (const MWWorld::Ptr& ptr, bool placeable=false);
|
||||
|
||||
void addActor (const MWWorld::Ptr& ptr);
|
||||
@ -108,6 +114,8 @@ namespace MWWorld
|
||||
|
||||
private:
|
||||
|
||||
void updateWater();
|
||||
|
||||
OEngine::Render::OgreRenderer &mRender;
|
||||
OEngine::Physic::PhysicEngine* mEngine;
|
||||
std::map<std::string, std::string> handleToMesh;
|
||||
@ -124,6 +132,12 @@ namespace MWWorld
|
||||
|
||||
float mTimeAccum;
|
||||
|
||||
float mWaterHeight;
|
||||
float mWaterEnabled;
|
||||
|
||||
std::auto_ptr<btCollisionObject> mWaterCollisionObject;
|
||||
std::auto_ptr<btCollisionShape> mWaterCollisionShape;
|
||||
|
||||
PhysicsSystem (const PhysicsSystem&);
|
||||
PhysicsSystem& operator= (const PhysicsSystem&);
|
||||
};
|
||||
|
@ -153,7 +153,8 @@ namespace MWWorld
|
||||
Ogre::Vector3 pos(it->mNode->getPosition());
|
||||
Ogre::Vector3 newPos = pos + direction * duration * speed;
|
||||
|
||||
it->mSound->setPosition(newPos);
|
||||
if (it->mSound.get())
|
||||
it->mSound->setPosition(newPos);
|
||||
|
||||
it->mNode->setPosition(newPos);
|
||||
|
||||
@ -163,7 +164,8 @@ namespace MWWorld
|
||||
// TODO: use a proper btRigidBody / btGhostObject?
|
||||
btVector3 from(pos.x, pos.y, pos.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;
|
||||
|
||||
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?
|
||||
btVector3 from(pos.x, pos.y, pos.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;
|
||||
|
||||
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();
|
||||
state.mSound = sndMgr->playManualSound3D(esm.mPosition, esm.mSound, 1.0f, 1.0f,
|
||||
MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
|
||||
state.mSoundId = esm.mSound;
|
||||
|
||||
mMagicBolts.push_back(state);
|
||||
return true;
|
||||
|
@ -83,7 +83,12 @@ namespace
|
||||
ptr.getClass().insertObject (ptr, mPhysics);
|
||||
|
||||
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);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
@ -233,6 +238,15 @@ namespace MWWorld
|
||||
insertCell (*cell, true, loadingListener);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1660,6 +1660,7 @@ namespace MWWorld
|
||||
|
||||
void World::setWaterHeight(const float height)
|
||||
{
|
||||
mPhysics->setWaterHeight(height);
|
||||
mRendering->setWaterHeight(height);
|
||||
}
|
||||
|
||||
@ -1994,7 +1995,7 @@ namespace MWWorld
|
||||
Ogre::Vector3 playerPos(refdata.getPosition().pos);
|
||||
|
||||
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;
|
||||
if((currentCell->getCell()->mData.mFlags&ESM::Cell::NoSleep) ||
|
||||
player.getClass().getNpcStats(player).isWerewolf())
|
||||
@ -3073,4 +3074,12 @@ namespace MWWorld
|
||||
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.
|
||||
virtual void resetActors();
|
||||
|
||||
virtual bool isWalkingOnWater (const MWWorld::Ptr& actor);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,8 @@ namespace Physic
|
||||
, mExternalCollisionMode(true)
|
||||
, mForce(0.0f)
|
||||
, mScale(scale)
|
||||
, mWalkingOnWater(false)
|
||||
, mCanWaterWalk(false)
|
||||
{
|
||||
if (!NifBullet::getBoundingBox(mMesh, mHalfExtents, mMeshTranslation, mMeshOrientation))
|
||||
{
|
||||
@ -103,8 +105,7 @@ namespace Physic
|
||||
setPosition(position);
|
||||
setRotation(rotation);
|
||||
|
||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
|
||||
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap);
|
||||
updateCollisionMask();
|
||||
}
|
||||
|
||||
PhysicActor::~PhysicActor()
|
||||
@ -123,10 +124,22 @@ namespace Physic
|
||||
|
||||
void PhysicActor::enableCollisionBody(bool collision)
|
||||
{
|
||||
assert(mBody);
|
||||
if(collision && !mExternalCollisionMode) enableCollisionBody();
|
||||
if(!collision && mExternalCollisionMode) disableCollisionBody();
|
||||
mExternalCollisionMode = collision;
|
||||
if (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
|
||||
@ -178,18 +191,23 @@ namespace Physic
|
||||
mOnGround = grounded;
|
||||
}
|
||||
|
||||
void PhysicActor::disableCollisionBody()
|
||||
bool PhysicActor::isWalkingOnWater() const
|
||||
{
|
||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
|
||||
CollisionType_World|CollisionType_HeightMap);
|
||||
return mWalkingOnWater;
|
||||
}
|
||||
|
||||
void PhysicActor::enableCollisionBody()
|
||||
void PhysicActor::setWalkingOnWater(bool walkingOnWater)
|
||||
{
|
||||
mEngine->mDynamicsWorld->removeRigidBody(mBody);
|
||||
mEngine->mDynamicsWorld->addRigidBody(mBody, CollisionType_Actor,
|
||||
CollisionType_Actor|CollisionType_World|CollisionType_HeightMap);
|
||||
mWalkingOnWater = walkingOnWater;
|
||||
}
|
||||
|
||||
void PhysicActor::setCanWaterWalk(bool waterWalk)
|
||||
{
|
||||
if (waterWalk != mCanWaterWalk)
|
||||
{
|
||||
mCanWaterWalk = waterWalk;
|
||||
updateCollisionMask();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -381,7 +399,7 @@ namespace Physic
|
||||
mHeightFieldMap [name] = hf;
|
||||
|
||||
mDynamicsWorld->addRigidBody(body,CollisionType_HeightMap,
|
||||
CollisionType_Actor|CollisionType_Raycasting);
|
||||
CollisionType_Actor|CollisionType_Raycasting|CollisionType_Projectile);
|
||||
}
|
||||
|
||||
void PhysicEngine::removeHeightField(int x, int y)
|
||||
@ -494,7 +512,7 @@ namespace Physic
|
||||
{
|
||||
assert (mRaycastingObjectMap.find(name) == mRaycastingObjectMap.end());
|
||||
mRaycastingObjectMap[name] = body;
|
||||
mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting);
|
||||
mDynamicsWorld->addRigidBody(body,CollisionType_Raycasting,CollisionType_Raycasting|CollisionType_Projectile);
|
||||
}
|
||||
|
||||
return body;
|
||||
@ -800,10 +818,10 @@ namespace Physic
|
||||
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;
|
||||
resultCallback1.m_collisionFilterGroup = 0xff;
|
||||
resultCallback1.m_collisionFilterGroup = filterGroup;
|
||||
resultCallback1.m_collisionFilterMask = CollisionType_Raycasting|CollisionType_Actor|CollisionType_HeightMap;
|
||||
mDynamicsWorld->rayTest(from, to, resultCallback1);
|
||||
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_Actor = 1<<1, //<Collide sith actors
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/// 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:
|
||||
void disableCollisionBody();
|
||||
void enableCollisionBody();
|
||||
/// Removes then re-adds the collision body to the dynamics world
|
||||
void updateCollisionMask();
|
||||
|
||||
bool mCanWaterWalk;
|
||||
bool mWalkingOnWater;
|
||||
|
||||
boost::shared_ptr<btCollisionShape> mShape;
|
||||
|
||||
@ -288,7 +301,7 @@ namespace Physic
|
||||
/**
|
||||
* 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);
|
||||
///< @return (hit, relative distance)
|
||||
|
Loading…
x
Reference in New Issue
Block a user