From 3669d0a99887d8663fbb14d64d5f318c717aff62 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sat, 27 Apr 2013 20:57:44 +0200 Subject: [PATCH 01/17] Bugfix #742 --- apps/openmw/mwworld/worldimp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index d3190e0b5e..7ceb3e2f72 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1453,7 +1453,7 @@ namespace MWWorld Ogre::Vector3 playerPos(refdata.getPosition().pos); const OEngine::Physic::PhysicActor *physactor = mPhysEngine->getCharacter(refdata.getHandle()); - if(!physactor->getOnGround() || isUnderwater(currentCell, playerPos)) + if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos)) return 2; if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) return 1; From 07891fa21385362be585479bc24a9e6d25957c99 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 07:53:04 +0200 Subject: [PATCH 02/17] Athletics skill increase --- apps/openmw/mwmechanics/character.cpp | 26 +++++++++++++++++++++++++- apps/openmw/mwmechanics/character.hpp | 4 ++++ apps/openmw/mwmechanics/npcstats.cpp | 3 +-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 86a2660332..b82fc4dc56 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -28,6 +28,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" +#include "../mwworld/player.hpp" #include "../mwworld/class.hpp" @@ -103,7 +104,7 @@ static void getStateInfo(CharacterState state, std::string *group) CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim, CharacterState state, bool loop) - : mPtr(ptr), mAnimation(anim), mCharState(state), mSkipAnim(false), mMovingAnim(false) + : mPtr(ptr), mAnimation(anim), mCharState(state), mSkipAnim(false), mMovingAnim(false), mSecondsOfRunning(0), mSecondsOfSwimming(0) { if(!mAnimation) return; @@ -152,6 +153,29 @@ void CharacterController::update(float duration, Movement &movement) const Ogre::Vector3 &rot = cls.getRotationVector(mPtr); speed = cls.getSpeed(mPtr); + // advance athletics + if (vec.squaredLength() > 0 && mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) + { + if (inwater) + { + mSecondsOfSwimming += duration; + while (mSecondsOfSwimming > 1) + { + MWWorld::Class::get(mPtr).skillUsageSucceeded(mPtr, ESM::Skill::Athletics, 1); + mSecondsOfSwimming -= 1; + } + } + else if (isrunning) + { + mSecondsOfRunning += duration; + while (mSecondsOfRunning > 1) + { + MWWorld::Class::get(mPtr).skillUsageSucceeded(mPtr, ESM::Skill::Athletics, 0); + mSecondsOfRunning -= 1; + } + } + } + /* FIXME: The state should be set to Jump, and X/Y movement should be disallowed except * for the initial thrust (which would be carried by "physics" until landing). */ if(onground && vec.z > 0.0f) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 7b26d6b346..4ee217d119 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -79,6 +79,10 @@ class CharacterController bool mLooping; bool mSkipAnim; + // counted for skill increase + float mSecondsOfSwimming; + float mSecondsOfRunning; + bool mMovingAnim; public: diff --git a/apps/openmw/mwmechanics/npcstats.cpp b/apps/openmw/mwmechanics/npcstats.cpp index 7216e8fe0e..def91a6c54 100644 --- a/apps/openmw/mwmechanics/npcstats.cpp +++ b/apps/openmw/mwmechanics/npcstats.cpp @@ -169,8 +169,7 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla if (specialisationFactor<=0) throw std::runtime_error ("invalid skill specialisation factor"); } - - return 1.0 / (level +1) * (1.0 / (skillFactor)) * typeFactor * specialisationFactor; + return 1.0 / ((level+1) * (1.0/skillFactor) * typeFactor * specialisationFactor); } void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType) From db78d15fc4d7329bc2531d00da24d53085bdec60 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 05:29:34 +0200 Subject: [PATCH 03/17] Fix changeWeather --- apps/openmw/mwworld/weather.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 3e85253123..d0ed835dc4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -289,7 +289,7 @@ void WeatherManager::update(float duration) if (exterior) { - std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion; + std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); Misc::StringUtils::toLower(regionstr); if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) @@ -621,6 +621,10 @@ unsigned int WeatherManager::getWeatherID() const void WeatherManager::changeWeather(const std::string& region, const unsigned int id) { + // make sure this region exists + const ESM::Region *reg = + MWBase::Environment::get().getWorld()->getStore().get().find(region); + std::string weather; if (id==0) weather = "clear"; @@ -645,5 +649,9 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int else weather = "clear"; - mRegionOverrides[region] = weather; + mRegionOverrides[Misc::StringUtils::lowerCase(region)] = weather; + + std::string playerRegion = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion; + if (Misc::StringUtils::ciEqual(region, playerRegion)) + setWeather(weather); } From fdf80c1c4f0e0e0456eedec99356cb067852bfae Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 11:05:01 +0200 Subject: [PATCH 04/17] Fix unused variable --- apps/openmw/mwworld/weather.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index d0ed835dc4..10d065cbc0 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -622,8 +622,7 @@ unsigned int WeatherManager::getWeatherID() const void WeatherManager::changeWeather(const std::string& region, const unsigned int id) { // make sure this region exists - const ESM::Region *reg = - MWBase::Environment::get().getWorld()->getStore().get().find(region); + MWBase::Environment::get().getWorld()->getStore().get().find(region); std::string weather; if (id==0) From 7d61459ccdb4b454cf8866e241f05169d56c7ef4 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 11:13:21 +0200 Subject: [PATCH 05/17] Added stub implementation for 'Fall'. There is no use for this function because our physics controller applies gravity constantly anyway. --- apps/openmw/mwscript/docs/vmformat.txt | 4 +++- apps/openmw/mwscript/miscextensions.cpp | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index be253b59b3..d02fc92898 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -329,5 +329,7 @@ op 0x2000206: Move op 0x2000207: Move, explicit op 0x2000208: MoveWorld op 0x2000209: MoveWorld, explicit +op 0x200020a: Fall +op 0x200020b: Fall, explicit -opcodes 0x200020a-0x3ffffff unused +opcodes 0x200020c-0x3ffffff unused diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 489f6bd3db..daf64c0d53 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -557,6 +557,16 @@ namespace MWScript } }; + template + class OpFall : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + } + }; + const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeActivate = 0x2000075; @@ -598,6 +608,8 @@ namespace MWScript const int opcodeSetDelete = 0x20001e5; const int opcodeSetDeleteExplicit = 0x20001e6; const int opcodeGetSquareRoot = 0x20001e7; + const int opcodeFall = 0x200020a; + const int opcodeFallExplicit = 0x200020b; const int opcodePlayBink = 0x20001f7; @@ -639,6 +651,7 @@ namespace MWScript extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime); extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit); extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot); + extensions.registerInstruction ("fall", "", opcodeFall, opcodeFallExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -685,6 +698,9 @@ namespace MWScript interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete); interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete); interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot); + interpreter.installSegment5 (opcodeFall, new OpFall); + interpreter.installSegment5 (opcodeFallExplicit, new OpFall); + } } } From 766d1efa845d23640e0680f8d7ccd1a41744466f Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 28 Apr 2013 11:41:01 +0100 Subject: [PATCH 06/17] Render weapon and shield. Only shield can be seen right now as weapons need to be drawed out. --- apps/openmw/mwrender/animation.cpp | 2 ++ apps/openmw/mwrender/animation.hpp | 2 ++ apps/openmw/mwrender/npcanimation.cpp | 30 ++++++++++++++++++++++++--- apps/openmw/mwrender/npcanimation.hpp | 5 +++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b4a219e387..39bffbded0 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -737,4 +737,6 @@ Ogre::Vector3 Animation::runAnimation(float duration) return movement; } +void Animation::showWeapons(bool showWeapon){} + } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 3b6cc4abf4..b2d4bc6e79 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -161,6 +161,8 @@ public: virtual Ogre::Vector3 runAnimation(float duration); + virtual void showWeapons(bool showWeapon); + /* Returns if there's an animation playing on the given layer. */ bool isPlaying(size_t layeridx) const { return mLayer[layeridx].mPlaying; } diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 27f1508f7a..09d4546bc9 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -30,7 +30,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize { ESM::PRT_LHand, "Left Hand" }, { ESM::PRT_RWrist, "Right Wrist" }, { ESM::PRT_LWrist, "Left Wrist" }, - { ESM::PRT_Shield, "Shield" }, + { ESM::PRT_Shield, "Shield Bone" }, { ESM::PRT_RForearm, "Right Forearm" }, { ESM::PRT_LForearm, "Left Forearm" }, { ESM::PRT_RUpperarm, "Right Upper Arm" }, @@ -45,7 +45,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize { ESM::PRT_LLeg, "Left Upper Leg" }, { ESM::PRT_RPauldron, "Right Clavicle" }, { ESM::PRT_LPauldron, "Left Clavicle" }, - { ESM::PRT_Weapon, "Weapon" }, + { ESM::PRT_Weapon, "Weapon Bone" }, { ESM::PRT_Tail, "Tail" } }; @@ -74,7 +74,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor mGloveL(inv.end()), mGloveR(inv.end()), mSkirtIter(inv.end()), - mViewMode(viewMode) + mWeapon(inv.end()), + mShield(inv.end()), + mViewMode(viewMode), + mShowWeapons(false) { mNpc = mPtr.get()->mBase; @@ -175,6 +178,7 @@ void NpcAnimation::updateParts(bool forceupdate) { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 }, { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 }, { &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, 0 }, + { &NpcAnimation::mShield, MWWorld::InventoryStore::Slot_CarriedLeft, 0 } }; static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]); @@ -333,6 +337,7 @@ void NpcAnimation::updateParts(bool forceupdate) if (mPartPriorities[part] < 1 && bodypart) addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); } + } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) @@ -464,4 +469,23 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vectorget())->mBase; + addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,"meshes\\"+weapon->mModel); + } + } + else + { + removeIndividualPart(ESM::PRT_Weapon); + } +} + } diff --git a/apps/openmw/mwrender/npcanimation.hpp b/apps/openmw/mwrender/npcanimation.hpp index f2f4c66697..e72fa56ed7 100644 --- a/apps/openmw/mwrender/npcanimation.hpp +++ b/apps/openmw/mwrender/npcanimation.hpp @@ -46,6 +46,7 @@ private: std::string mHairModel; std::string mBodyPrefix; ViewMode mViewMode; + bool mShowWeapons; float mTimeToChange; MWWorld::ContainerStoreIterator mRobe; @@ -60,6 +61,8 @@ private: MWWorld::ContainerStoreIterator mGloveL; MWWorld::ContainerStoreIterator mGloveR; MWWorld::ContainerStoreIterator mSkirtIter; + MWWorld::ContainerStoreIterator mWeapon; + MWWorld::ContainerStoreIterator mShield; int mVisibilityFlags; @@ -85,6 +88,8 @@ public: virtual Ogre::Vector3 runAnimation(float timepassed); + virtual void showWeapons(bool showWeapon); + void setViewMode(ViewMode viewMode); void forceUpdate() From 5388c25e648cb3af79b785637c86bb9cd8d0ae7e Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 28 Apr 2013 11:55:50 +0100 Subject: [PATCH 07/17] Fix or lockpicks. --- apps/openmw/mwrender/npcanimation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 09d4546bc9..d6bc22cc05 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -478,8 +478,8 @@ void NpcAnimation::showWeapons(bool showWeapon) mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); if(mWeapon != inv.end()) // special case for weapons { - const ESM::Weapon* weapon = (mWeapon->get())->mBase; - addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,"meshes\\"+weapon->mModel); + std::string mesh = MWWorld::Class::get(*mWeapon).getModel(*mWeapon); + addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,mesh); } } else From 3d9ceede77b5e3e08f6be7d265f4d4b49e8c6271 Mon Sep 17 00:00:00 2001 From: gus Date: Sun, 28 Apr 2013 12:33:41 +0100 Subject: [PATCH 08/17] little fix (weapons disapeared when tab was pressed) --- apps/openmw/mwrender/npcanimation.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index d6bc22cc05..1d1ebf6b63 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -338,6 +338,7 @@ void NpcAnimation::updateParts(bool forceupdate) addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); } + showWeapons(mShowWeapons); } NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) From 738a54337d724971d48ea34ccb75d0016fa657c1 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sun, 28 Apr 2013 14:07:53 +0200 Subject: [PATCH 09/17] removed redundant case smashing --- apps/openmw/mwworld/weather.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 10d065cbc0..c940398fab 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -290,7 +290,6 @@ void WeatherManager::update(float duration) if (exterior) { std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion); - Misc::StringUtils::toLower(regionstr); if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion) { From 9343b4459e42f25c9ab657153c0ee431e985c520 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 14:59:15 +0200 Subject: [PATCH 10/17] Opening doors --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwclass/door.cpp | 14 +++---- apps/openmw/mwworld/actiondoor.cpp | 16 ++++++++ apps/openmw/mwworld/actiondoor.hpp | 18 +++++++++ apps/openmw/mwworld/physicssystem.cpp | 6 ++- apps/openmw/mwworld/physicssystem.hpp | 1 + apps/openmw/mwworld/worldimp.cpp | 56 ++++++++++++++++++++++++++- apps/openmw/mwworld/worldimp.hpp | 6 +++ libs/openengine/bullet/physic.cpp | 23 +++++++++++ libs/openengine/bullet/physic.hpp | 2 + 11 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 apps/openmw/mwworld/actiondoor.cpp create mode 100644 apps/openmw/mwworld/actiondoor.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index f4fdcb390e..08033f8228 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -54,7 +54,7 @@ add_openmw_dir (mwworld containerstore actiontalk actiontake manualref player cellfunctors failedaction cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat - esmstore store recordcmp fallback actionrepair actionsoulgem livecellref + esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor ) add_openmw_dir (mwclass diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a00ae9c3c4..42821e3617 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -326,6 +326,9 @@ namespace MWBase virtual void setupPlayer(bool newGame) = 0; virtual void renderPlayer() = 0; + virtual void activateDoor(const MWWorld::Ptr& door) = 0; + ///< activate (open or close) an non-teleport door + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0; virtual int canRest() = 0; diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 163cf02775..5b061e090b 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -12,6 +12,7 @@ #include "../mwworld/nullaction.hpp" #include "../mwworld/failedaction.hpp" #include "../mwworld/actionteleport.hpp" +#include "../mwworld/actiondoor.hpp" #include "../mwworld/cellstore.hpp" #include "../mwworld/physicssystem.hpp" #include "../mwworld/inventorystore.hpp" @@ -71,7 +72,7 @@ namespace MWClass ptr.get(); const std::string &openSound = ref->mBase->mOpenSound; - //const std::string &closeSound = ref->mBase->closeSound; + const std::string &closeSound = ref->mBase->mCloseSound; const std::string lockedSound = "LockedDoor"; const std::string trapActivationSound = "Disarm Trap Fail"; @@ -139,12 +140,11 @@ namespace MWClass else { // animated door - // TODO return action for rotating the door - - // This is a little pointless, but helps with testing - boost::shared_ptr action(new MWWorld::NullAction); - - action->setSound(openSound); + boost::shared_ptr action(new MWWorld::ActionDoor(ptr)); + if (ptr.getRefData().getLocalRotation().rot[2] == 0) + action->setSound(openSound); + else + action->setSound(closeSound); return action; } diff --git a/apps/openmw/mwworld/actiondoor.cpp b/apps/openmw/mwworld/actiondoor.cpp new file mode 100644 index 0000000000..6e3441e220 --- /dev/null +++ b/apps/openmw/mwworld/actiondoor.cpp @@ -0,0 +1,16 @@ +#include "actiondoor.hpp" + +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + +namespace MWWorld +{ + ActionDoor::ActionDoor (const MWWorld::Ptr& object) : Action (false, object) + { + } + + void ActionDoor::executeImp (const MWWorld::Ptr& actor) + { + MWBase::Environment::get().getWorld()->activateDoor(getTarget()); + } +} diff --git a/apps/openmw/mwworld/actiondoor.hpp b/apps/openmw/mwworld/actiondoor.hpp new file mode 100644 index 0000000000..2dc5ad8c13 --- /dev/null +++ b/apps/openmw/mwworld/actiondoor.hpp @@ -0,0 +1,18 @@ +#ifndef GAME_MWWORLD_ACTIONDOOR_H +#define GAME_MWWORLD_ACTIONDOOR_H + +#include "action.hpp" +#include "ptr.hpp" + +namespace MWWorld +{ + class ActionDoor : public Action + { + virtual void executeImp (const MWWorld::Ptr& actor); + + public: + ActionDoor (const Ptr& object); + }; +} + +#endif diff --git a/apps/openmw/mwworld/physicssystem.cpp b/apps/openmw/mwworld/physicssystem.cpp index 19ee2e517b..34e6036e6d 100644 --- a/apps/openmw/mwworld/physicssystem.cpp +++ b/apps/openmw/mwworld/physicssystem.cpp @@ -131,7 +131,6 @@ namespace MWWorld return position; } - static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity, OEngine::Physic::PhysicEngine *engine) { @@ -390,6 +389,11 @@ namespace MWWorld } } + std::vector PhysicsSystem::getCollisions(const Ptr &ptr) + { + return mEngine->getCollisions(ptr.getRefData().getBaseNode()->getName()); + } + Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity) { return MovementSolver::move(ptr, movement, time, gravity, mEngine); diff --git a/apps/openmw/mwworld/physicssystem.hpp b/apps/openmw/mwworld/physicssystem.hpp index 4eec9367cb..48214029e1 100644 --- a/apps/openmw/mwworld/physicssystem.hpp +++ b/apps/openmw/mwworld/physicssystem.hpp @@ -51,6 +51,7 @@ namespace MWWorld bool toggleCollisionMode(); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); + std::vector getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); std::pair getFacedHandle (MWWorld::World& world, float queryDistance); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7ceb3e2f72..e4f28ecc51 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -978,7 +978,45 @@ namespace MWWorld !isSwimming(player->first) && !isFlying(player->first)); moveObjectImp(player->first, vec.x, vec.y, vec.z); } - // the only purpose this has currently is to update the debug drawer + + // doors + for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) + { + if (!it->first.getRefData().getCount()) + mDoorStates.erase(it); + else + { + if (mPlayer->getPlayer().getCell() != it->first.getCell()) + continue; + float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); + float diff = duration * 90 * (it->second ? 1 : -1); + float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); + localRotateObject(it->first, 0, 0, targetRot); + + std::vector collisions = mPhysics->getCollisions(it->first); + for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) + { + MWWorld::Ptr ptr = getPtrViaHandle(*cit); + if (MWWorld::Class::get(ptr).isActor()) + { + // figure out which side of the door the object we collided with is + Ogre::Vector3 relativePos = it->first.getRefData().getBaseNode()-> + convertWorldToLocalPosition(ptr.getRefData().getBaseNode()->_getDerivedPosition()); + if(relativePos.y >= 0) + targetRot = std::min(std::max(0.f, oldRot + diff*0.1f), 90.f); + else + targetRot = std::min(std::max(0.f, oldRot - diff*0.1f), 90.f); + + localRotateObject(it->first, 0, 0, targetRot); + break; + } + } + + if ((targetRot == 90.f && it->second) || targetRot == 0.f) + mDoorStates.erase(it); + } + } + mPhysEngine->stepSimulation (duration); } @@ -1480,4 +1518,20 @@ namespace MWWorld { mRendering->frameStarted(dt); } + + void World::activateDoor(const MWWorld::Ptr& door) + { + if (mDoorStates.find(door) != mDoorStates.end()) + { + // if currently opening, then close, if closing, then open + mDoorStates[door] = !mDoorStates[door]; + } + else + { + if (door.getRefData().getLocalRotation().rot[2] == 0) + mDoorStates[door] = 1; // open + else + mDoorStates[door] = 0; // close + } + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index a51bdc2e69..35c53e29e5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -85,6 +85,9 @@ namespace MWWorld float mFaced2Distance; int mNumFacing; + std::map mDoorStates; + ///< only holds doors that are currently moving. 0 means closing, 1 opening + unsigned long lastTick; Ogre::Timer mTimer; @@ -368,6 +371,9 @@ namespace MWWorld virtual void setupPlayer(bool newGame); virtual void renderPlayer(); + virtual void activateDoor(const MWWorld::Ptr& door); + ///< activate (open or close) an non-teleport door + virtual void setupExternalRendering (MWRender::ExternalRendering& rendering); virtual int canRest(); diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index eaeae7dc39..d522ebaf80 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -509,6 +509,29 @@ namespace Physic } } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback + { + public: + std::vector mResult; + virtual btScalar addSingleResult(btManifoldPoint& cp, + const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, + const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) + { + const RigidBody* body = dynamic_cast(colObj0Wrap->m_collisionObject); + if (body) + mResult.push_back(body->mName); + return 0.f; + } + }; + + std::vector PhysicEngine::getCollisions(const std::string& name) + { + RigidBody* body = getRigidBody(name); + ContactTestResultCallback callback; + dynamicsWorld->contactTest(body, callback); + return callback.mResult; + } + void PhysicEngine::stepSimulation(double deltaT) { // This seems to be needed for character controller objects diff --git a/libs/openengine/bullet/physic.hpp b/libs/openengine/bullet/physic.hpp index 6ce4edba35..6d88fcb559 100644 --- a/libs/openengine/bullet/physic.hpp +++ b/libs/openengine/bullet/physic.hpp @@ -298,6 +298,8 @@ namespace Physic */ std::vector< std::pair > rayTest2(btVector3& from, btVector3& to); + std::vector getCollisions(const std::string& name); + //event list of non player object std::list NPEventList; From 4ee1a6ee02eb604d53062d34c92801bf9e1c2204 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 15:36:37 +0200 Subject: [PATCH 11/17] Put door physics in a separate method, some fixes --- apps/openmw/mwworld/worldimp.cpp | 16 +++++++++++----- apps/openmw/mwworld/worldimp.hpp | 3 +++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e4f28ecc51..ffa87f58c9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -979,15 +979,23 @@ namespace MWWorld moveObjectImp(player->first, vec.x, vec.y, vec.z); } + processDoors(duration); + + mPhysEngine->stepSimulation (duration); + } + + void World::processDoors(float duration) + { // doors for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) { - if (!it->first.getRefData().getCount()) - mDoorStates.erase(it); + if (it->first.isEmpty() || !it->first.getRefData().getCount()) + mDoorStates.erase(it++); else { - if (mPlayer->getPlayer().getCell() != it->first.getCell()) + if (!mWorldScene->isCellActive(*it->first.getCell())) continue; + float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); float diff = duration * 90 * (it->second ? 1 : -1); float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); @@ -1016,8 +1024,6 @@ namespace MWWorld mDoorStates.erase(it); } } - - mPhysEngine->stepSimulation (duration); } bool World::toggleCollisionMode() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 35c53e29e5..172ae406cd 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -272,6 +272,9 @@ namespace MWWorld virtual void doPhysics(const PtrMovementList &actors, float duration); ///< Run physics simulation and modify \a world accordingly. + virtual void processDoors(float duration); + ///< Run physics simulation and modify \a world accordingly. + virtual bool toggleCollisionMode(); ///< Toggle collision mode for player. If disabled player object should ignore /// collisions and gravity. From 208f9ca8c550da17baa23e9ae1f8aff8b4d017f5 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 15:56:09 +0200 Subject: [PATCH 12/17] Fix problem with newer (or older?) bullet version (thanks travis) --- libs/openengine/bullet/physic.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index d522ebaf80..b41da093d0 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -522,6 +522,15 @@ namespace Physic mResult.push_back(body->mName); return 0.f; } + + virtual btScalar addSingleResult(btManifoldPoint&, const btCollisionObject* col0, int partId0, int index0, + const btCollisionObject* col1, int partId1, int index1) + { + const RigidBody* body = dynamic_cast(col0); + if (body) + mResult.push_back(body->mName); + return 0.f; + } }; std::vector PhysicEngine::getCollisions(const std::string& name) From 6ecd88af1426cf406f0fcb92261ad15a785f74be Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 15:59:59 +0200 Subject: [PATCH 13/17] More fixes --- apps/openmw/mwworld/worldimp.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ffa87f58c9..6fc7324e51 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -986,19 +986,16 @@ namespace MWWorld void World::processDoors(float duration) { - // doors - for (std::map::iterator it = mDoorStates.begin(); it != mDoorStates.end(); ++it) + std::map::iterator it = mDoorStates.begin(); + while (it != mDoorStates.end()) { - if (it->first.isEmpty() || !it->first.getRefData().getCount()) + if (!mWorldScene->isCellActive(*it->first.getCell())) mDoorStates.erase(it++); else { - if (!mWorldScene->isCellActive(*it->first.getCell())) - continue; - float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees(); - float diff = duration * 90 * (it->second ? 1 : -1); - float targetRot = std::min(std::max(0.f, oldRot + diff), 90.f); + float diff = duration * 90; + float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second ? 1 : -1)), 90.f); localRotateObject(it->first, 0, 0, targetRot); std::vector collisions = mPhysics->getCollisions(it->first); @@ -1021,7 +1018,9 @@ namespace MWWorld } if ((targetRot == 90.f && it->second) || targetRot == 0.f) - mDoorStates.erase(it); + mDoorStates.erase(it++); + else + ++it; } } } From 2e1dda9010f8434a8ab91913eeea218338be58d1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 16:19:40 +0200 Subject: [PATCH 14/17] Fix old bullet versions --- libs/openengine/bullet/physic.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libs/openengine/bullet/physic.cpp b/libs/openengine/bullet/physic.cpp index b41da093d0..dbb42a6456 100644 --- a/libs/openengine/bullet/physic.cpp +++ b/libs/openengine/bullet/physic.cpp @@ -513,7 +513,11 @@ namespace Physic { public: std::vector mResult; - virtual btScalar addSingleResult(btManifoldPoint& cp, + + // added in bullet 2.81 + // this is just a quick hack, as there does not seem to be a BULLET_VERSION macro? +#if defined(BT_COLLISION_OBJECT_WRAPPER_H) + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0, const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) { @@ -522,8 +526,8 @@ namespace Physic mResult.push_back(body->mName); return 0.f; } - - virtual btScalar addSingleResult(btManifoldPoint&, const btCollisionObject* col0, int partId0, int index0, +#else + virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { const RigidBody* body = dynamic_cast(col0); @@ -531,6 +535,7 @@ namespace Physic mResult.push_back(body->mName); return 0.f; } +#endif }; std::vector PhysicEngine::getCollisions(const std::string& name) From 98baf9fac190d2793b50ee499ff5d03c575a19ce Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 28 Apr 2013 16:36:12 +0200 Subject: [PATCH 15/17] Bugfix #718 --- apps/openmw/mwworld/store.cpp | 38 ++++++++++++++++++++++++++++++++--- components/esm/loadcell.cpp | 33 ++++-------------------------- components/esm/loadcell.hpp | 3 ++- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 005601cd13..ebc7ef03f6 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -1,4 +1,5 @@ #include "store.hpp" +#include "esmstore.hpp" namespace MWWorld { @@ -15,8 +16,39 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) ESM::Cell *cell = new ESM::Cell; cell->mName = id; - // The cell itself takes care of some of the hairy details - cell->load(esm, *mEsmStore); + //First part of cell loading + cell->preLoad(esm); + + //Handling MovedCellRefs, there is no way to do it inside loadcell + while (esm.isNextSub("MVRF")) { + ESM::CellRef ref; + ESM::MovedCellRef cMRef; + cell->getNextMVRF(esm, cMRef); + + MWWorld::Store &cStore = const_cast&>(mEsmStore->get()); + ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + cell->getNextRef(esm, ref); + std::string lowerCase; + + std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + // Add data required to make reference appear in the correct cell. + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + cell->mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); + else + *iter = ref; + } + + //Second part of cell loading + cell->postLoad(esm); if(cell->mData.mFlags & ESM::Cell::Interior) { @@ -62,4 +94,4 @@ void Store::load(ESM::ESMReader &esm, const std::string &id) delete cell; } -} \ No newline at end of file +} diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 77e4d3691c..27d3208870 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -132,38 +132,13 @@ void Cell::load(ESMReader &esm, bool saveContext) } } -void Cell::load(ESMReader &esm, MWWorld::ESMStore &store) +void Cell::preLoad(ESMReader &esm) //Can't be "load" because it conflicts with function in esmtool { this->load(esm, false); +} - // preload moved references - while (esm.isNextSub("MVRF")) { - CellRef ref; - MovedCellRef cMRef; - getNextMVRF(esm, cMRef); - - MWWorld::Store &cStore = const_cast&>(store.get()); - ESM::Cell *cellAlt = const_cast(cStore.searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - - // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following - // implementation when the oher implementation works as well. - getNextRef(esm, ref); - std::string lowerCase; - - std::transform (ref.mRefID.begin(), ref.mRefID.end(), std::back_inserter (lowerCase), - (int(*)(int)) std::tolower); - - // Add data required to make reference appear in the correct cell. - // We should not need to test for duplicates, as this part of the code is pre-cell merge. - mMovedRefs.push_back(cMRef); - // But there may be duplicates here! - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefnum); - if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(ref); - else - *iter = ref; - } - +void Cell::postLoad(ESMReader &esm) +{ // Save position of the cell references and move on mContextList.push_back(esm.getContext()); esm.skipRecord(); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index d7f64817f8..eda8a5418c 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -96,7 +96,8 @@ struct Cell CellRefTracker mLeasedRefs; MovedCellRefTracker mMovedRefs; - void load(ESMReader &esm, MWWorld::ESMStore &store); + void preLoad(ESMReader &esm); + void postLoad(ESMReader &esm); // This method is left in for compatibility with esmtool. Parsing moved references currently requires // passing ESMStore, bit it does not know about this parameter, so we do it this way. From 6ea82333d4b269af59724408d41533b3ac5b0a42 Mon Sep 17 00:00:00 2001 From: Glorf Date: Sun, 28 Apr 2013 16:38:33 +0200 Subject: [PATCH 16/17] Headers cleanup --- components/esm/loadcell.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/esm/loadcell.cpp b/components/esm/loadcell.cpp index 27d3208870..779f303f3e 100644 --- a/components/esm/loadcell.cpp +++ b/components/esm/loadcell.cpp @@ -8,9 +8,6 @@ #include "esmreader.hpp" #include "esmwriter.hpp" -#include -#include - namespace ESM { From 67e5e939a113c17589351f83140d177f76c558aa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 28 Apr 2013 17:57:36 +0200 Subject: [PATCH 17/17] Fix some doors --- apps/openmw/mwworld/worldimp.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6fc7324e51..f1fd020df2 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -998,19 +998,28 @@ namespace MWWorld float targetRot = std::min(std::max(0.f, oldRot + diff * (it->second ? 1 : -1)), 90.f); localRotateObject(it->first, 0, 0, targetRot); + // AABB of the door + Ogre::Vector3 min,max; + mPhysics->getObjectAABB(it->first, min, max); + Ogre::Vector3 dimensions = max-min; + std::vector collisions = mPhysics->getCollisions(it->first); for (std::vector::iterator cit = collisions.begin(); cit != collisions.end(); ++cit) { MWWorld::Ptr ptr = getPtrViaHandle(*cit); if (MWWorld::Class::get(ptr).isActor()) { - // figure out which side of the door the object we collided with is + // we collided with an actor, we need to undo the rotation and push the door away from the actor + + // figure out on which side of the door the actor we collided with is Ogre::Vector3 relativePos = it->first.getRefData().getBaseNode()-> convertWorldToLocalPosition(ptr.getRefData().getBaseNode()->_getDerivedPosition()); - if(relativePos.y >= 0) - targetRot = std::min(std::max(0.f, oldRot + diff*0.1f), 90.f); + + float axisToCheck = (dimensions.x > dimensions.y) ? relativePos.y : -relativePos.x; + if (axisToCheck >= 0) + targetRot = std::min(std::max(0.f, oldRot + diff*0.5f), 90.f); else - targetRot = std::min(std::max(0.f, oldRot - diff*0.1f), 90.f); + targetRot = std::min(std::max(0.f, oldRot - diff*0.5f), 90.f); localRotateObject(it->first, 0, 0, targetRot); break;