Merge remote-tracking branch 'zini/master' into animations

actorid
Chris Robinson 12 years ago
commit 24e503330b

@ -54,7 +54,7 @@ add_openmw_dir (mwworld
containerstore actiontalk actiontake manualref player cellfunctors failedaction containerstore actiontalk actiontake manualref player cellfunctors failedaction
cells localscripts customdata weather inventorystore ptr actionopen actionread cells localscripts customdata weather inventorystore ptr actionopen actionread
actionequip timestamp actionalchemy cellstore actionapply actioneat 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 add_openmw_dir (mwclass

@ -326,6 +326,9 @@ namespace MWBase
virtual void setupPlayer(bool newGame) = 0; virtual void setupPlayer(bool newGame) = 0;
virtual void renderPlayer() = 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 void setupExternalRendering (MWRender::ExternalRendering& rendering) = 0;
virtual int canRest() = 0; virtual int canRest() = 0;

@ -12,6 +12,7 @@
#include "../mwworld/nullaction.hpp" #include "../mwworld/nullaction.hpp"
#include "../mwworld/failedaction.hpp" #include "../mwworld/failedaction.hpp"
#include "../mwworld/actionteleport.hpp" #include "../mwworld/actionteleport.hpp"
#include "../mwworld/actiondoor.hpp"
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "../mwworld/physicssystem.hpp" #include "../mwworld/physicssystem.hpp"
#include "../mwworld/inventorystore.hpp" #include "../mwworld/inventorystore.hpp"
@ -71,7 +72,7 @@ namespace MWClass
ptr.get<ESM::Door>(); ptr.get<ESM::Door>();
const std::string &openSound = ref->mBase->mOpenSound; 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 lockedSound = "LockedDoor";
const std::string trapActivationSound = "Disarm Trap Fail"; const std::string trapActivationSound = "Disarm Trap Fail";
@ -139,12 +140,11 @@ namespace MWClass
else else
{ {
// animated door // animated door
// TODO return action for rotating the door boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr));
if (ptr.getRefData().getLocalRotation().rot[2] == 0)
// This is a little pointless, but helps with testing action->setSound(openSound);
boost::shared_ptr<MWWorld::Action> action(new MWWorld::NullAction); else
action->setSound(closeSound);
action->setSound(openSound);
return action; return action;
} }

@ -28,6 +28,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp" #include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.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) 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) if(!mAnimation)
return; return;
@ -152,6 +153,29 @@ void CharacterController::update(float duration, Movement &movement)
const Ogre::Vector3 &rot = cls.getRotationVector(mPtr); const Ogre::Vector3 &rot = cls.getRotationVector(mPtr);
speed = cls.getSpeed(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 /* 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). */ * for the initial thrust (which would be carried by "physics" until landing). */
if(onground && vec.z > 0.0f) if(onground && vec.z > 0.0f)

@ -79,6 +79,10 @@ class CharacterController
bool mLooping; bool mLooping;
bool mSkipAnim; bool mSkipAnim;
// counted for skill increase
float mSecondsOfSwimming;
float mSecondsOfRunning;
bool mMovingAnim; bool mMovingAnim;
public: public:

@ -169,8 +169,7 @@ float MWMechanics::NpcStats::getSkillGain (int skillIndex, const ESM::Class& cla
if (specialisationFactor<=0) if (specialisationFactor<=0)
throw std::runtime_error ("invalid skill specialisation factor"); 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) void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType)

@ -737,4 +737,6 @@ Ogre::Vector3 Animation::runAnimation(float duration)
return movement; return movement;
} }
void Animation::showWeapons(bool showWeapon){}
} }

@ -161,6 +161,8 @@ public:
virtual Ogre::Vector3 runAnimation(float duration); virtual Ogre::Vector3 runAnimation(float duration);
virtual void showWeapons(bool showWeapon);
/* Returns if there's an animation playing on the given layer. */ /* Returns if there's an animation playing on the given layer. */
bool isPlaying(size_t layeridx) const bool isPlaying(size_t layeridx) const
{ return mLayer[layeridx].mPlaying; } { return mLayer[layeridx].mPlaying; }

@ -30,7 +30,7 @@ const NpcAnimation::PartInfo NpcAnimation::sPartList[NpcAnimation::sPartListSize
{ ESM::PRT_LHand, "Left Hand" }, { ESM::PRT_LHand, "Left Hand" },
{ ESM::PRT_RWrist, "Right Wrist" }, { ESM::PRT_RWrist, "Right Wrist" },
{ ESM::PRT_LWrist, "Left Wrist" }, { ESM::PRT_LWrist, "Left Wrist" },
{ ESM::PRT_Shield, "Shield" }, { ESM::PRT_Shield, "Shield Bone" },
{ ESM::PRT_RForearm, "Right Forearm" }, { ESM::PRT_RForearm, "Right Forearm" },
{ ESM::PRT_LForearm, "Left Forearm" }, { ESM::PRT_LForearm, "Left Forearm" },
{ ESM::PRT_RUpperarm, "Right Upper Arm" }, { 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_LLeg, "Left Upper Leg" },
{ ESM::PRT_RPauldron, "Right Clavicle" }, { ESM::PRT_RPauldron, "Right Clavicle" },
{ ESM::PRT_LPauldron, "Left Clavicle" }, { ESM::PRT_LPauldron, "Left Clavicle" },
{ ESM::PRT_Weapon, "Weapon" }, { ESM::PRT_Weapon, "Weapon Bone" },
{ ESM::PRT_Tail, "Tail" } { ESM::PRT_Tail, "Tail" }
}; };
@ -74,7 +74,10 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, Ogre::SceneNode* node, MWWor
mGloveL(inv.end()), mGloveL(inv.end()),
mGloveR(inv.end()), mGloveR(inv.end()),
mSkirtIter(inv.end()), mSkirtIter(inv.end()),
mViewMode(viewMode) mWeapon(inv.end()),
mShield(inv.end()),
mViewMode(viewMode),
mShowWeapons(false)
{ {
mNpc = mPtr.get<ESM::NPC>()->mBase; mNpc = mPtr.get<ESM::NPC>()->mBase;
@ -175,6 +178,7 @@ void NpcAnimation::updateParts(bool forceupdate)
{ &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 }, { &NpcAnimation::mGloveR, MWWorld::InventoryStore::Slot_RightGauntlet, 0 },
{ &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 }, { &NpcAnimation::mShirt, MWWorld::InventoryStore::Slot_Shirt, 0 },
{ &NpcAnimation::mPants, MWWorld::InventoryStore::Slot_Pants, 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]); static const size_t slotlistsize = sizeof(slotlist)/sizeof(slotlist[0]);
@ -333,6 +337,8 @@ void NpcAnimation::updateParts(bool forceupdate)
if (mPartPriorities[part] < 1 && bodypart) if (mPartPriorities[part] < 1 && bodypart)
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel); addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
} }
showWeapons(mShowWeapons);
} }
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename) NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
@ -464,4 +470,23 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
} }
} }
void NpcAnimation::showWeapons(bool showWeapon)
{
mShowWeapons = showWeapon;
if(showWeapon)
{
MWWorld::InventoryStore &inv = MWWorld::Class::get(mPtr).getInventoryStore(mPtr);
mWeapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(mWeapon != inv.end()) // special case for weapons
{
std::string mesh = MWWorld::Class::get(*mWeapon).getModel(*mWeapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon,-1,1,mesh);
}
}
else
{
removeIndividualPart(ESM::PRT_Weapon);
}
}
} }

@ -46,6 +46,7 @@ private:
std::string mHairModel; std::string mHairModel;
std::string mBodyPrefix; std::string mBodyPrefix;
ViewMode mViewMode; ViewMode mViewMode;
bool mShowWeapons;
float mTimeToChange; float mTimeToChange;
MWWorld::ContainerStoreIterator mRobe; MWWorld::ContainerStoreIterator mRobe;
@ -60,6 +61,8 @@ private:
MWWorld::ContainerStoreIterator mGloveL; MWWorld::ContainerStoreIterator mGloveL;
MWWorld::ContainerStoreIterator mGloveR; MWWorld::ContainerStoreIterator mGloveR;
MWWorld::ContainerStoreIterator mSkirtIter; MWWorld::ContainerStoreIterator mSkirtIter;
MWWorld::ContainerStoreIterator mWeapon;
MWWorld::ContainerStoreIterator mShield;
int mVisibilityFlags; int mVisibilityFlags;
@ -85,6 +88,8 @@ public:
virtual Ogre::Vector3 runAnimation(float timepassed); virtual Ogre::Vector3 runAnimation(float timepassed);
virtual void showWeapons(bool showWeapon);
void setViewMode(ViewMode viewMode); void setViewMode(ViewMode viewMode);
void forceUpdate() void forceUpdate()

@ -329,5 +329,7 @@ op 0x2000206: Move
op 0x2000207: Move, explicit op 0x2000207: Move, explicit
op 0x2000208: MoveWorld op 0x2000208: MoveWorld
op 0x2000209: MoveWorld, explicit op 0x2000209: MoveWorld, explicit
op 0x200020a: Fall
op 0x200020b: Fall, explicit
opcodes 0x200020a-0x3ffffff unused opcodes 0x200020c-0x3ffffff unused

@ -555,6 +555,16 @@ namespace MWScript
} }
}; };
template <class R>
class OpFall : public Interpreter::Opcode0
{
public:
virtual void execute (Interpreter::Runtime& runtime)
{
}
};
const int opcodeXBox = 0x200000c; const int opcodeXBox = 0x200000c;
const int opcodeOnActivate = 0x200000d; const int opcodeOnActivate = 0x200000d;
const int opcodeActivate = 0x2000075; const int opcodeActivate = 0x2000075;
@ -596,6 +606,8 @@ namespace MWScript
const int opcodeSetDelete = 0x20001e5; const int opcodeSetDelete = 0x20001e5;
const int opcodeSetDeleteExplicit = 0x20001e6; const int opcodeSetDeleteExplicit = 0x20001e6;
const int opcodeGetSquareRoot = 0x20001e7; const int opcodeGetSquareRoot = 0x20001e7;
const int opcodeFall = 0x200020a;
const int opcodeFallExplicit = 0x200020b;
const int opcodePlayBink = 0x20001f7; const int opcodePlayBink = 0x20001f7;
@ -637,6 +649,7 @@ namespace MWScript
extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime); extensions.registerFunction ("getcurrenttime", 'f', "", opcodeGetCurrentTime);
extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit); extensions.registerInstruction ("setdelete", "l", opcodeSetDelete, opcodeSetDeleteExplicit);
extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot); extensions.registerFunction ("getsquareroot", 'f', "f", opcodeGetSquareRoot);
extensions.registerInstruction ("fall", "", opcodeFall, opcodeFallExplicit);
} }
void installOpcodes (Interpreter::Interpreter& interpreter) void installOpcodes (Interpreter::Interpreter& interpreter)
@ -683,6 +696,9 @@ namespace MWScript
interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete<ImplicitRef>); interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete<ImplicitRef>);
interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete<ExplicitRef>); interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete<ExplicitRef>);
interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot); interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot);
interpreter.installSegment5 (opcodeFall, new OpFall<ImplicitRef>);
interpreter.installSegment5 (opcodeFallExplicit, new OpFall<ExplicitRef>);
} }
} }
} }

@ -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());
}
}

@ -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

@ -131,7 +131,6 @@ namespace MWWorld
return position; return position;
} }
static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, static Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time,
bool gravity, OEngine::Physic::PhysicEngine *engine) bool gravity, OEngine::Physic::PhysicEngine *engine)
{ {
@ -390,6 +389,11 @@ namespace MWWorld
} }
} }
std::vector<std::string> 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) Ogre::Vector3 PhysicsSystem::move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity)
{ {
return MovementSolver::move(ptr, movement, time, gravity, mEngine); return MovementSolver::move(ptr, movement, time, gravity, mEngine);

@ -51,6 +51,7 @@ namespace MWWorld
bool toggleCollisionMode(); bool toggleCollisionMode();
Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity); Ogre::Vector3 move(const MWWorld::Ptr &ptr, const Ogre::Vector3 &movement, float time, bool gravity);
std::vector<std::string> getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with
Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr); Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr);
std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance); std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance);

@ -1,4 +1,5 @@
#include "store.hpp" #include "store.hpp"
#include "esmstore.hpp"
namespace MWWorld { namespace MWWorld {
@ -15,8 +16,39 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
ESM::Cell *cell = new ESM::Cell; ESM::Cell *cell = new ESM::Cell;
cell->mName = id; cell->mName = id;
// The cell itself takes care of some of the hairy details //First part of cell loading
cell->load(esm, *mEsmStore); 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<ESM::Cell> &cStore = const_cast<MWWorld::Store<ESM::Cell>&>(mEsmStore->get<ESM::Cell>());
ESM::Cell *cellAlt = const_cast<ESM::Cell*>(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) if(cell->mData.mFlags & ESM::Cell::Interior)
{ {
@ -62,4 +94,4 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
delete cell; delete cell;
} }
} }

@ -289,8 +289,7 @@ void WeatherManager::update(float duration)
if (exterior) 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) if (mWeatherUpdateTime <= 0 || regionstr != mCurrentRegion)
{ {
@ -621,6 +620,9 @@ unsigned int WeatherManager::getWeatherID() const
void WeatherManager::changeWeather(const std::string& region, const unsigned int id) void WeatherManager::changeWeather(const std::string& region, const unsigned int id)
{ {
// make sure this region exists
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().find(region);
std::string weather; std::string weather;
if (id==0) if (id==0)
weather = "clear"; weather = "clear";
@ -645,5 +647,9 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int
else else
weather = "clear"; 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);
} }

@ -995,10 +995,62 @@ namespace MWWorld
!isSwimming(player->first) && !isFlying(player->first)); !isSwimming(player->first) && !isFlying(player->first));
moveObjectImp(player->first, vec.x, vec.y, vec.z); moveObjectImp(player->first, vec.x, vec.y, vec.z);
} }
// the only purpose this has currently is to update the debug drawer
processDoors(duration);
mPhysEngine->stepSimulation (duration); mPhysEngine->stepSimulation (duration);
} }
void World::processDoors(float duration)
{
std::map<MWWorld::Ptr, int>::iterator it = mDoorStates.begin();
while (it != mDoorStates.end())
{
if (!mWorldScene->isCellActive(*it->first.getCell()))
mDoorStates.erase(it++);
else
{
float oldRot = Ogre::Radian(it->first.getRefData().getLocalRotation().rot[2]).valueDegrees();
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);
// AABB of the door
Ogre::Vector3 min,max;
mPhysics->getObjectAABB(it->first, min, max);
Ogre::Vector3 dimensions = max-min;
std::vector<std::string> collisions = mPhysics->getCollisions(it->first);
for (std::vector<std::string>::iterator cit = collisions.begin(); cit != collisions.end(); ++cit)
{
MWWorld::Ptr ptr = getPtrViaHandle(*cit);
if (MWWorld::Class::get(ptr).isActor())
{
// 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());
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.5f), 90.f);
localRotateObject(it->first, 0, 0, targetRot);
break;
}
}
if ((targetRot == 90.f && it->second) || targetRot == 0.f)
mDoorStates.erase(it++);
else
++it;
}
}
}
bool World::toggleCollisionMode() bool World::toggleCollisionMode()
{ {
return mPhysics->toggleCollisionMode();; return mPhysics->toggleCollisionMode();;
@ -1470,7 +1522,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() || isUnderwater(currentCell, playerPos)) if((!physactor->getOnGround()&&physactor->getCollisionMode()) || isUnderwater(currentCell, playerPos))
return 2; return 2;
if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep)) if((currentCell->mCell->mData.mFlags&ESM::Cell::NoSleep))
return 1; return 1;
@ -1497,4 +1549,20 @@ namespace MWWorld
{ {
mRendering->frameStarted(dt); 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
}
}
} }

@ -85,6 +85,9 @@ namespace MWWorld
float mFaced2Distance; float mFaced2Distance;
int mNumFacing; int mNumFacing;
std::map<MWWorld::Ptr, int> mDoorStates;
///< only holds doors that are currently moving. 0 means closing, 1 opening
unsigned long lastTick; unsigned long lastTick;
Ogre::Timer mTimer; Ogre::Timer mTimer;
@ -269,6 +272,9 @@ namespace MWWorld
virtual void doPhysics(const PtrMovementList &actors, float duration); virtual void doPhysics(const PtrMovementList &actors, float duration);
///< Run physics simulation and modify \a world accordingly. ///< Run physics simulation and modify \a world accordingly.
virtual void processDoors(float duration);
///< Run physics simulation and modify \a world accordingly.
virtual bool toggleCollisionMode(); virtual bool toggleCollisionMode();
///< Toggle collision mode for player. If disabled player object should ignore ///< Toggle collision mode for player. If disabled player object should ignore
/// collisions and gravity. /// collisions and gravity.
@ -368,6 +374,9 @@ namespace MWWorld
virtual void setupPlayer(bool newGame); virtual void setupPlayer(bool newGame);
virtual void renderPlayer(); 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 void setupExternalRendering (MWRender::ExternalRendering& rendering);
virtual int canRest(); virtual int canRest();

@ -8,9 +8,6 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
#include <apps/openmw/mwworld/store.hpp>
#include <apps/openmw/mwworld/cellstore.hpp>
namespace ESM namespace ESM
{ {
@ -132,38 +129,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); this->load(esm, false);
}
// preload moved references void Cell::postLoad(ESMReader &esm)
while (esm.isNextSub("MVRF")) { {
CellRef ref;
MovedCellRef cMRef;
getNextMVRF(esm, cMRef);
MWWorld::Store<ESM::Cell> &cStore = const_cast<MWWorld::Store<ESM::Cell>&>(store.get<ESM::Cell>());
ESM::Cell *cellAlt = const_cast<ESM::Cell*>(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;
}
// Save position of the cell references and move on // Save position of the cell references and move on
mContextList.push_back(esm.getContext()); mContextList.push_back(esm.getContext());
esm.skipRecord(); esm.skipRecord();

@ -96,7 +96,8 @@ struct Cell
CellRefTracker mLeasedRefs; CellRefTracker mLeasedRefs;
MovedCellRefTracker mMovedRefs; 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 // 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. // passing ESMStore, bit it does not know about this parameter, so we do it this way.

@ -509,6 +509,43 @@ namespace Physic
} }
} }
class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback
{
public:
std::vector<std::string> mResult;
// 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)
{
const RigidBody* body = dynamic_cast<const RigidBody*>(colObj0Wrap->m_collisionObject);
if (body)
mResult.push_back(body->mName);
return 0.f;
}
#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<const RigidBody*>(col0);
if (body)
mResult.push_back(body->mName);
return 0.f;
}
#endif
};
std::vector<std::string> PhysicEngine::getCollisions(const std::string& name)
{
RigidBody* body = getRigidBody(name);
ContactTestResultCallback callback;
dynamicsWorld->contactTest(body, callback);
return callback.mResult;
}
void PhysicEngine::stepSimulation(double deltaT) void PhysicEngine::stepSimulation(double deltaT)
{ {
// This seems to be needed for character controller objects // This seems to be needed for character controller objects

@ -298,6 +298,8 @@ namespace Physic
*/ */
std::vector< std::pair<float, std::string> > rayTest2(btVector3& from, btVector3& to); std::vector< std::pair<float, std::string> > rayTest2(btVector3& from, btVector3& to);
std::vector<std::string> getCollisions(const std::string& name);
//event list of non player object //event list of non player object
std::list<PhysicEvent> NPEventList; std::list<PhysicEvent> NPEventList;

Loading…
Cancel
Save