mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 21:23:52 +00:00
Merge remote-tracking branch 'zini/master' into animations
This commit is contained in:
commit
24e503330b
24 changed files with 305 additions and 57 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<ESM::Door>();
|
||||
|
||||
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<MWWorld::Action> action(new MWWorld::NullAction);
|
||||
|
||||
action->setSound(openSound);
|
||||
boost::shared_ptr<MWWorld::Action> action(new MWWorld::ActionDoor(ptr));
|
||||
if (ptr.getRefData().getLocalRotation().rot[2] == 0)
|
||||
action->setSound(openSound);
|
||||
else
|
||||
action->setSound(closeSound);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -79,6 +79,10 @@ class CharacterController
|
|||
bool mLooping;
|
||||
bool mSkipAnim;
|
||||
|
||||
// counted for skill increase
|
||||
float mSecondsOfSwimming;
|
||||
float mSecondsOfRunning;
|
||||
|
||||
bool mMovingAnim;
|
||||
|
||||
public:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -737,4 +737,6 @@ Ogre::Vector3 Animation::runAnimation(float duration)
|
|||
return movement;
|
||||
}
|
||||
|
||||
void Animation::showWeapons(bool showWeapon){}
|
||||
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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<ESM::NPC>()->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,8 @@ void NpcAnimation::updateParts(bool forceupdate)
|
|||
if (mPartPriorities[part] < 1 && bodypart)
|
||||
addOrReplaceIndividualPart(part, -1,1, "meshes\\"+bodypart->mModel);
|
||||
}
|
||||
|
||||
showWeapons(mShowWeapons);
|
||||
}
|
||||
|
||||
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 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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 opcodeOnActivate = 0x200000d;
|
||||
const int opcodeActivate = 0x2000075;
|
||||
|
@ -596,6 +606,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;
|
||||
|
||||
|
@ -637,6 +649,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)
|
||||
|
@ -683,6 +696,9 @@ namespace MWScript
|
|||
interpreter.installSegment5 (opcodeSetDelete, new OpSetDelete<ImplicitRef>);
|
||||
interpreter.installSegment5 (opcodeSetDeleteExplicit, new OpSetDelete<ExplicitRef>);
|
||||
interpreter.installSegment5 (opcodeGetSquareRoot, new OpGetSquareRoot);
|
||||
interpreter.installSegment5 (opcodeFall, new OpFall<ImplicitRef>);
|
||||
interpreter.installSegment5 (opcodeFallExplicit, new OpFall<ExplicitRef>);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
apps/openmw/mwworld/actiondoor.cpp
Normal file
16
apps/openmw/mwworld/actiondoor.cpp
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
18
apps/openmw/mwworld/actiondoor.hpp
Normal file
18
apps/openmw/mwworld/actiondoor.hpp
Normal file
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
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<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)
|
||||
{
|
||||
return MovementSolver::move(ptr, movement, time, gravity, mEngine);
|
||||
|
|
|
@ -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<std::string> getCollisions(const MWWorld::Ptr &ptr); ///< get handles this object collides with
|
||||
Ogre::Vector3 traceDown(const MWWorld::Ptr &ptr);
|
||||
|
||||
std::pair<float, std::string> getFacedHandle (MWWorld::World& world, float queryDistance);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "store.hpp"
|
||||
#include "esmstore.hpp"
|
||||
|
||||
namespace MWWorld {
|
||||
|
||||
|
@ -15,8 +16,39 @@ void Store<ESM::Cell>::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<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)
|
||||
{
|
||||
|
@ -62,4 +94,4 @@ void Store<ESM::Cell>::load(ESM::ESMReader &esm, const std::string &id)
|
|||
delete cell;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -289,8 +289,7 @@ void WeatherManager::update(float duration)
|
|||
|
||||
if (exterior)
|
||||
{
|
||||
std::string regionstr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion;
|
||||
Misc::StringUtils::toLower(regionstr);
|
||||
std::string regionstr = Misc::StringUtils::lowerCase(MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell()->mCell->mRegion);
|
||||
|
||||
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)
|
||||
{
|
||||
// make sure this region exists
|
||||
MWBase::Environment::get().getWorld()->getStore().get<ESM::Region>().find(region);
|
||||
|
||||
std::string weather;
|
||||
if (id==0)
|
||||
weather = "clear";
|
||||
|
@ -645,5 +647,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);
|
||||
}
|
||||
|
|
|
@ -995,10 +995,62 @@ 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
|
||||
|
||||
processDoors(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()
|
||||
{
|
||||
return mPhysics->toggleCollisionMode();;
|
||||
|
@ -1470,7 +1522,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;
|
||||
|
@ -1497,4 +1549,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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,9 @@ namespace MWWorld
|
|||
float mFaced2Distance;
|
||||
int mNumFacing;
|
||||
|
||||
std::map<MWWorld::Ptr, int> mDoorStates;
|
||||
///< only holds doors that are currently moving. 0 means closing, 1 opening
|
||||
|
||||
unsigned long lastTick;
|
||||
Ogre::Timer mTimer;
|
||||
|
||||
|
@ -269,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.
|
||||
|
@ -368,6 +374,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();
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
#include <apps/openmw/mwworld/store.hpp>
|
||||
#include <apps/openmw/mwworld/cellstore.hpp>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// preload moved references
|
||||
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;
|
||||
}
|
||||
|
||||
void Cell::postLoad(ESMReader &esm)
|
||||
{
|
||||
// Save position of the cell references and move on
|
||||
mContextList.push_back(esm.getContext());
|
||||
esm.skipRecord();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
// 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::string> getCollisions(const std::string& name);
|
||||
|
||||
//event list of non player object
|
||||
std::list<PhysicEvent> NPEventList;
|
||||
|
||||
|
|
Loading…
Reference in a new issue