mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-04 00:26:45 +00:00 
			
		
		
		
	Feature #50: Spawn projectiles
Fix a bug in copyObjectToCell. Make actor rotations more consistent.
This commit is contained in:
		
							parent
							
								
									f36bea03ab
								
							
						
					
					
						commit
						12de0afb03
					
				
					 16 changed files with 295 additions and 127 deletions
				
			
		| 
						 | 
				
			
			@ -274,7 +274,7 @@ namespace MWBase
 | 
			
		|||
            virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
 | 
			
		||||
 | 
			
		||||
            virtual void
 | 
			
		||||
            moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore &newCell, float x, float y, float z) = 0;
 | 
			
		||||
            moveObject(const MWWorld::Ptr &ptr, MWWorld::CellStore* newCell, float x, float y, float z) = 0;
 | 
			
		||||
 | 
			
		||||
            virtual void scaleObject (const MWWorld::Ptr& ptr, float scale) = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -282,7 +282,7 @@ namespace MWBase
 | 
			
		|||
 | 
			
		||||
            virtual void localRotateObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0;
 | 
			
		||||
 | 
			
		||||
            virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) = 0;
 | 
			
		||||
            virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos) = 0;
 | 
			
		||||
            ///< place an object in a "safe" location (ie not in the void, etc).
 | 
			
		||||
 | 
			
		||||
            virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
 | 
			
		||||
| 
						 | 
				
			
			@ -464,8 +464,10 @@ namespace MWBase
 | 
			
		|||
 | 
			
		||||
            virtual void castSpell (const MWWorld::Ptr& actor) = 0;
 | 
			
		||||
 | 
			
		||||
            virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
 | 
			
		||||
            virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
 | 
			
		||||
                                           const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
 | 
			
		||||
            virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
 | 
			
		||||
                                           const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
 | 
			
		||||
 | 
			
		||||
            virtual const std::vector<std::string>& getContentFiles() const = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -57,7 +57,7 @@ namespace MWClass
 | 
			
		|||
                MWWorld::ManualRef ref(store, id);
 | 
			
		||||
                ref.getPtr().getCellRef().mPos = ptr.getCellRef().mPos;
 | 
			
		||||
                // TODO: hold on to this for respawn purposes later
 | 
			
		||||
                MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), *ptr.getCell() , ptr.getCellRef().mPos);
 | 
			
		||||
                MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(), ptr.getCell() , ptr.getCellRef().mPos);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ptr.getRefData().setCustomData(data.release());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -578,13 +578,13 @@ namespace MWInput
 | 
			
		|||
            float rot[3];
 | 
			
		||||
            rot[0] = -y;
 | 
			
		||||
            rot[1] = 0.0f;
 | 
			
		||||
            rot[2] = x;
 | 
			
		||||
            rot[2] = -x;
 | 
			
		||||
 | 
			
		||||
            // Only actually turn player when we're not in vanity mode
 | 
			
		||||
            if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
 | 
			
		||||
            {
 | 
			
		||||
                mPlayer->yaw(x);
 | 
			
		||||
                mPlayer->pitch(-y);
 | 
			
		||||
                mPlayer->pitch(y);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (arg.zrel && mControlSwitch["playerviewswitch"]) //Check to make sure you are allowed to zoomout and there is a change
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -210,7 +210,7 @@ namespace MWMechanics
 | 
			
		|||
                    && LOS
 | 
			
		||||
                    )
 | 
			
		||||
                {
 | 
			
		||||
                    creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayer().getPlayer()));
 | 
			
		||||
                    creatureStats.getAiSequence().stack(AiCombat(MWBase::Environment::get().getWorld()->getPlayerPtr()));
 | 
			
		||||
                    creatureStats.setHostile(true);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -541,7 +541,7 @@ namespace MWMechanics
 | 
			
		|||
                        // TODO: Add AI to follow player and fight for him
 | 
			
		||||
                        // TODO: VFX_SummonStart, VFX_SummonEnd
 | 
			
		||||
                        creatureStats.mSummonedCreatures.insert(std::make_pair(it->first,
 | 
			
		||||
                            MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos).getRefData().getHandle()));
 | 
			
		||||
                            MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos).getRefData().getHandle()));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -313,6 +313,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
 | 
			
		|||
 | 
			
		||||
        mAnimation->disable(mCurrentMovement);
 | 
			
		||||
        mCurrentMovement = movement;
 | 
			
		||||
        mMovementAnimVelocity = 0.0f;
 | 
			
		||||
        if(!mCurrentMovement.empty())
 | 
			
		||||
        {
 | 
			
		||||
            float vel, speedmult = 1.0f;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,7 +321,10 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
 | 
			
		|||
            bool isrunning = mPtr.getClass().getCreatureStats(mPtr).getStance(MWMechanics::CreatureStats::Stance_Run);
 | 
			
		||||
 | 
			
		||||
            if(mMovementSpeed > 0.0f && (vel=mAnimation->getVelocity(mCurrentMovement)) > 1.0f)
 | 
			
		||||
            {
 | 
			
		||||
                mMovementAnimVelocity = vel;
 | 
			
		||||
                speedmult = mMovementSpeed / vel;
 | 
			
		||||
            }
 | 
			
		||||
            else if (mMovementState == CharState_TurnLeft || mMovementState == CharState_TurnRight)
 | 
			
		||||
                speedmult = 1.f; // TODO: should get a speed mult depending on the current turning speed
 | 
			
		||||
            else if (mMovementSpeed > 0.0f)
 | 
			
		||||
| 
						 | 
				
			
			@ -330,10 +334,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat
 | 
			
		|||
                speedmult = mMovementSpeed / (isrunning ? 222.857f : 154.064f);
 | 
			
		||||
            mAnimation->play(mCurrentMovement, Priority_Movement, movegroup, false,
 | 
			
		||||
                             speedmult, ((mode!=2)?"start":"loop start"), "stop", 0.0f, ~0ul);
 | 
			
		||||
 | 
			
		||||
            mMovementAnimVelocity = vel;
 | 
			
		||||
        }
 | 
			
		||||
        else mMovementAnimVelocity = 0.0f;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1194,7 +1195,10 @@ void CharacterController::update(float duration)
 | 
			
		|||
                                         : (sneak ? CharState_SneakBack
 | 
			
		||||
                                                  : (isrunning ? CharState_RunBack : CharState_WalkBack)));
 | 
			
		||||
            }
 | 
			
		||||
            else if(rot.z != 0.0f && !inwater && !sneak)
 | 
			
		||||
            // Don't play turning animations during attack. It would break positioning of the arrow bone when releasing a shot.
 | 
			
		||||
            // Actually, in vanilla the turning animation is not even played when merely having equipped the weapon,
 | 
			
		||||
            // but I don't think we need to go as far as that.
 | 
			
		||||
            else if(rot.z != 0.0f && !inwater && !sneak && mUpperBodyState < UpperCharState_StartToMinAttack)
 | 
			
		||||
            {
 | 
			
		||||
                if(rot.z > 0.0f)
 | 
			
		||||
                    movestate = CharState_TurnRight;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -587,7 +587,7 @@ namespace MWMechanics
 | 
			
		|||
                inflict(mTarget, mCaster, enchantment->mEffects, ESM::RT_Touch);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MWBase::Environment::get().getWorld()->launchProjectile(mId, false, enchantment->mEffects, mCaster, mSourceName);
 | 
			
		||||
        MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, enchantment->mEffects, mCaster, mSourceName);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -666,7 +666,7 @@ namespace MWMechanics
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MWBase::Environment::get().getWorld()->launchProjectile(mId, false, spell->mEffects, mCaster, mSourceName);
 | 
			
		||||
        MWBase::Environment::get().getWorld()->launchMagicBolt(mId, false, spell->mEffects, mCaster, mSourceName);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ namespace MWRender
 | 
			
		|||
        if (!mVanity.enabled && !mPreviewMode) {
 | 
			
		||||
            mCamera->getParentNode()->setOrientation(xr);
 | 
			
		||||
        } else {
 | 
			
		||||
            Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::NEGATIVE_UNIT_Z);
 | 
			
		||||
            Ogre::Quaternion zr(Ogre::Radian(getYaw()), Ogre::Vector3::UNIT_Z);
 | 
			
		||||
            mCamera->getParentNode()->setOrientation(zr * xr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -532,7 +532,7 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
 | 
			
		|||
    {
 | 
			
		||||
        float pitch = mPtr.getRefData().getPosition().rot[0];
 | 
			
		||||
        Ogre::Node *node = baseinst->getBone("Bip01 Neck");
 | 
			
		||||
        node->pitch(Ogre::Radian(pitch), Ogre::Node::TS_WORLD);
 | 
			
		||||
        node->pitch(Ogre::Radian(-pitch), Ogre::Node::TS_WORLD);
 | 
			
		||||
 | 
			
		||||
        // This has to be done before this function ends;
 | 
			
		||||
        // updateSkeletonInstance, below, touches the hands.
 | 
			
		||||
| 
						 | 
				
			
			@ -543,9 +543,9 @@ Ogre::Vector3 NpcAnimation::runAnimation(float timepassed)
 | 
			
		|||
        // In third person mode we may still need pitch for ranged weapon targeting
 | 
			
		||||
        float pitch = mPtr.getRefData().getPosition().rot[0] * mPitchFactor;
 | 
			
		||||
        Ogre::Node *node = baseinst->getBone("Bip01 Spine2");
 | 
			
		||||
        node->pitch(Ogre::Radian(pitch/2), Ogre::Node::TS_WORLD);
 | 
			
		||||
        node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
 | 
			
		||||
        node = baseinst->getBone("Bip01 Spine1");
 | 
			
		||||
        node->pitch(Ogre::Radian(pitch/2), Ogre::Node::TS_WORLD);
 | 
			
		||||
        node->pitch(Ogre::Radian(-pitch/2), Ogre::Node::TS_WORLD);
 | 
			
		||||
    }
 | 
			
		||||
    mFirstPersonOffset = 0.f; // reset the X, Y, Z offset for the next frame.
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -770,12 +770,35 @@ void NpcAnimation::attachArrow()
 | 
			
		|||
 | 
			
		||||
void NpcAnimation::releaseArrow()
 | 
			
		||||
{
 | 
			
		||||
    // Thrown weapons get detached now
 | 
			
		||||
    MWWorld::InventoryStore& inv = mPtr.getClass().getInventoryStore(mPtr);
 | 
			
		||||
    MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
 | 
			
		||||
    if (weapon != inv.end() && weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
 | 
			
		||||
    if (weapon == inv.end())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    // The orientation of the launched projectile. Always the same as the actor orientation, even if the ArrowBone's orientation dictates otherwise.
 | 
			
		||||
    Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(mPtr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
 | 
			
		||||
 | 
			
		||||
    if (weapon->get<ESM::Weapon>()->mBase->mData.mType == ESM::Weapon::MarksmanThrown)
 | 
			
		||||
    {
 | 
			
		||||
        // Thrown weapons get detached now
 | 
			
		||||
        NifOgre::ObjectScenePtr objects = mObjectParts[ESM::PRT_Weapon];
 | 
			
		||||
 | 
			
		||||
        Ogre::Vector3 launchPos(0,0,0);
 | 
			
		||||
        if (objects->mSkelBase)
 | 
			
		||||
        {
 | 
			
		||||
            launchPos = objects->mSkelBase->getParentNode()->_getDerivedPosition();
 | 
			
		||||
        }
 | 
			
		||||
        else if (objects->mEntities.size())
 | 
			
		||||
        {
 | 
			
		||||
            objects->mEntities[0]->getParentNode()->needUpdate(true);
 | 
			
		||||
            launchPos = objects->mEntities[0]->getParentNode()->_getDerivedPosition();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *weapon, launchPos, orient, *weapon, 400);
 | 
			
		||||
 | 
			
		||||
        showWeapons(false);
 | 
			
		||||
 | 
			
		||||
        inv.remove(*weapon, 1, mPtr);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
| 
						 | 
				
			
			@ -784,6 +807,21 @@ void NpcAnimation::releaseArrow()
 | 
			
		|||
        MWWorld::ContainerStoreIterator ammo = inv.getSlot(MWWorld::InventoryStore::Slot_Ammunition);
 | 
			
		||||
        if (ammo == inv.end())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Ogre::Vector3 launchPos(0,0,0);
 | 
			
		||||
        if (mAmmunition->mSkelBase)
 | 
			
		||||
        {
 | 
			
		||||
            launchPos = mAmmunition->mSkelBase->getParentNode()->_getDerivedPosition();
 | 
			
		||||
        }
 | 
			
		||||
        else if (mAmmunition->mEntities.size())
 | 
			
		||||
        {
 | 
			
		||||
            mAmmunition->mEntities[0]->getParentNode()->needUpdate(true);
 | 
			
		||||
            launchPos = mAmmunition->mEntities[0]->getParentNode()->_getDerivedPosition();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// \todo speed
 | 
			
		||||
        MWBase::Environment::get().getWorld()->launchProjectile(mPtr, *ammo, launchPos, orient, *weapon, 400);
 | 
			
		||||
 | 
			
		||||
        inv.remove(*ammo, 1, mPtr);
 | 
			
		||||
        mAmmunition.setNull();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -280,13 +280,12 @@ void RenderingManager::rotateObject(const MWWorld::Ptr &ptr)
 | 
			
		|||
 | 
			
		||||
    if(ptr.getRefData().getHandle() == mCamera->getHandle() &&
 | 
			
		||||
       !mCamera->isVanityOrPreviewModeEnabled())
 | 
			
		||||
        mCamera->rotateCamera(rot, false);
 | 
			
		||||
        mCamera->rotateCamera(-rot, false);
 | 
			
		||||
 | 
			
		||||
    Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
 | 
			
		||||
    Ogre::Quaternion newo = Ogre::Quaternion(Ogre::Radian(rot.z), Ogre::Vector3::NEGATIVE_UNIT_Z);
 | 
			
		||||
    if(!MWWorld::Class::get(ptr).isActor())
 | 
			
		||||
        newo = Ogre::Quaternion(Ogre::Radian(-rot.x), Ogre::Vector3::UNIT_X) *
 | 
			
		||||
               Ogre::Quaternion(Ogre::Radian(-rot.y), Ogre::Vector3::UNIT_Y) * newo;
 | 
			
		||||
 | 
			
		||||
        newo = Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::NEGATIVE_UNIT_X) *
 | 
			
		||||
               Ogre::Quaternion(Ogre::Radian(rot.y), Ogre::Vector3::NEGATIVE_UNIT_Y) * newo;
 | 
			
		||||
    ptr.getRefData().getBaseNode()->setOrientation(newo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -82,27 +82,21 @@ namespace MWScript
 | 
			
		|||
                    Interpreter::Type_Float angle = runtime[0].mFloat;
 | 
			
		||||
                    runtime.pop();
 | 
			
		||||
 | 
			
		||||
                    float ax = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees();
 | 
			
		||||
                    float ay = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees();
 | 
			
		||||
                    float az = Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees();
 | 
			
		||||
 | 
			
		||||
                    float *objRot = ptr.getRefData().getPosition().rot;
 | 
			
		||||
 | 
			
		||||
                    float lx = Ogre::Radian(objRot[0]).valueDegrees();
 | 
			
		||||
                    float ly = Ogre::Radian(objRot[1]).valueDegrees();
 | 
			
		||||
                    float lz = Ogre::Radian(objRot[2]).valueDegrees();
 | 
			
		||||
                    float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees();
 | 
			
		||||
                    float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
 | 
			
		||||
                    float az = Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees();
 | 
			
		||||
 | 
			
		||||
                    if (axis == "x")
 | 
			
		||||
                    {
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->localRotateObject(ptr,angle-lx,ay,az);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->rotateObject(ptr,angle,ay,az);
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (axis == "y")
 | 
			
		||||
                    {
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,angle-ly,az);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,angle,az);
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (axis == "z")
 | 
			
		||||
                    {
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->localRotateObject(ptr,ax,ay,angle-lz);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,angle);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                        throw std::runtime_error ("invalid ration axis: " + axis);
 | 
			
		||||
| 
						 | 
				
			
			@ -152,15 +146,15 @@ namespace MWScript
 | 
			
		|||
 | 
			
		||||
                    if (axis=="x")
 | 
			
		||||
                    {
 | 
			
		||||
                        runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[0]).valueDegrees()+Ogre::Radian(ptr.getRefData().getLocalRotation().rot[0]).valueDegrees());
 | 
			
		||||
                        runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees());
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (axis=="y")
 | 
			
		||||
                    {
 | 
			
		||||
                        runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[1]).valueDegrees()+Ogre::Radian(ptr.getRefData().getLocalRotation().rot[1]).valueDegrees());
 | 
			
		||||
                        runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees());
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (axis=="z")
 | 
			
		||||
                    {
 | 
			
		||||
                        runtime.push(Ogre::Radian(ptr.getCellRef().mPos.rot[2]).valueDegrees()+Ogre::Radian(ptr.getRefData().getLocalRotation().rot[2]).valueDegrees());
 | 
			
		||||
                        runtime.push(Ogre::Radian(ptr.getRefData().getPosition().rot[2]).valueDegrees());
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                        throw std::runtime_error ("invalid ration axis: " + axis);
 | 
			
		||||
| 
						 | 
				
			
			@ -313,7 +307,7 @@ namespace MWScript
 | 
			
		|||
                    }
 | 
			
		||||
                    if(store)
 | 
			
		||||
                    {
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->moveObject(ptr,*store,x,y,z);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z);
 | 
			
		||||
                        float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees();
 | 
			
		||||
                        float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
 | 
			
		||||
                        if(ptr.getTypeName() == typeid(ESM::NPC).name())//some morrowind oddity
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +355,7 @@ namespace MWScript
 | 
			
		|||
                    int cx,cy;
 | 
			
		||||
                    MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy);
 | 
			
		||||
                    MWBase::Environment::get().getWorld()->moveObject(ptr,
 | 
			
		||||
                        *MWBase::Environment::get().getWorld()->getExterior(cx,cy),x,y,z);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->getExterior(cx,cy),x,y,z);
 | 
			
		||||
                    float ax = Ogre::Radian(ptr.getRefData().getPosition().rot[0]).valueDegrees();
 | 
			
		||||
                    float ay = Ogre::Radian(ptr.getRefData().getPosition().rot[1]).valueDegrees();
 | 
			
		||||
                    if(ptr.getTypeName() == typeid(ESM::NPC).name())//some morrowind oddity
 | 
			
		||||
| 
						 | 
				
			
			@ -421,7 +415,7 @@ namespace MWScript
 | 
			
		|||
                        pos.rot[2]  = zRot;
 | 
			
		||||
                        MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID);
 | 
			
		||||
                        ref.getPtr().getCellRef().mPos = pos;
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,pos);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
| 
						 | 
				
			
			@ -462,7 +456,7 @@ namespace MWScript
 | 
			
		|||
                        pos.rot[2]  = zRot;
 | 
			
		||||
                        MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID);
 | 
			
		||||
                        ref.getPtr().getCellRef().mPos = pos;
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,pos);
 | 
			
		||||
                        MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,pos);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
| 
						 | 
				
			
			@ -530,7 +524,7 @@ namespace MWScript
 | 
			
		|||
                    MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), itemID, count);
 | 
			
		||||
                    ref.getPtr().getCellRef().mPos = ipos;
 | 
			
		||||
 | 
			
		||||
                    MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos);
 | 
			
		||||
                    MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),store,ipos);
 | 
			
		||||
                }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -148,7 +148,7 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot
 | 
			
		|||
 | 
			
		||||
    MWBase::World& world = *MWBase::Environment::get().getWorld();
 | 
			
		||||
 | 
			
		||||
    MWWorld::Ptr player = world.getPlayer().getPlayer();
 | 
			
		||||
    MWWorld::Ptr player = world.getPlayerPtr();
 | 
			
		||||
 | 
			
		||||
    profile.mContentFiles = world.getContentFiles();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -300,7 +300,7 @@ void MWState::StateManager::loadGame (const Character *character, const Slot *sl
 | 
			
		|||
        MWBase::Environment::get().getWindowManager()->updatePlayer();
 | 
			
		||||
        MWBase::Environment::get().getMechanicsManager()->playerLoaded();
 | 
			
		||||
 | 
			
		||||
        MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
 | 
			
		||||
        MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
 | 
			
		||||
 | 
			
		||||
        ESM::CellId cellId = ptr.getCell()->getCell()->getCellId();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,11 +41,11 @@ namespace MWWorld
 | 
			
		|||
                int cellX;
 | 
			
		||||
                int cellY;
 | 
			
		||||
                world->positionToIndex(mPosition.pos[0],mPosition.pos[1],cellX,cellY);
 | 
			
		||||
                world->moveObject(actor,*world->getExterior(cellX,cellY),
 | 
			
		||||
                world->moveObject(actor,world->getExterior(cellX,cellY),
 | 
			
		||||
                    mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                world->moveObject(actor,*world->getInterior(mCellName),mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]);
 | 
			
		||||
                world->moveObject(actor,world->getInterior(mCellName),mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,11 +120,9 @@ namespace MWWorld
 | 
			
		|||
            OEngine::Physic::PhysicActor *physicActor = engine->getCharacter(ptr.getRefData().getHandle());
 | 
			
		||||
            if(!physicActor || !physicActor->getCollisionMode())
 | 
			
		||||
            {
 | 
			
		||||
                // FIXME: This works, but it's inconcsistent with how the rotations are applied elsewhere. Why?
 | 
			
		||||
                return position + (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*
 | 
			
		||||
                                   Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
 | 
			
		||||
                                   Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) *
 | 
			
		||||
                                  movement * time;
 | 
			
		||||
                return position +  (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
 | 
			
		||||
                                    Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X))
 | 
			
		||||
                                * movement * time;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            btCollisionObject *colobj = physicActor->getCollisionBody();
 | 
			
		||||
| 
						 | 
				
			
			@ -140,14 +138,12 @@ namespace MWWorld
 | 
			
		|||
            Ogre::Vector3 velocity;
 | 
			
		||||
            if(position.z < waterlevel || isFlying)
 | 
			
		||||
            {
 | 
			
		||||
                velocity = (Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z)*
 | 
			
		||||
                            Ogre::Quaternion(Ogre::Radian(-refpos.rot[1]), Ogre::Vector3::UNIT_Y)*
 | 
			
		||||
                            Ogre::Quaternion(Ogre::Radian( refpos.rot[0]), Ogre::Vector3::UNIT_X)) *
 | 
			
		||||
                           movement;
 | 
			
		||||
                velocity = (Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z)*
 | 
			
		||||
                            Ogre::Quaternion(Ogre::Radian(refpos.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)) * movement;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                velocity = Ogre::Quaternion(Ogre::Radian(-refpos.rot[2]), Ogre::Vector3::UNIT_Z) * movement;
 | 
			
		||||
                velocity = Ogre::Quaternion(Ogre::Radian(refpos.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) * movement;
 | 
			
		||||
                if(!physicActor->getOnGround())
 | 
			
		||||
                {
 | 
			
		||||
                    // If falling, add part of the incoming velocity with the current inertia
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,6 +228,7 @@ namespace MWWorld
 | 
			
		|||
 | 
			
		||||
        mCells.clear();
 | 
			
		||||
 | 
			
		||||
        mMagicBolts.clear();
 | 
			
		||||
        mProjectiles.clear();
 | 
			
		||||
        mDoorStates.clear();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -821,7 +822,7 @@ namespace MWWorld
 | 
			
		|||
        const ESM::Position &posdata = ptr.getRefData().getPosition();
 | 
			
		||||
        Ogre::Vector3 pos(posdata.pos);
 | 
			
		||||
        Ogre::Quaternion rot = Ogre::Quaternion(Ogre::Radian(posdata.rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
 | 
			
		||||
                               Ogre::Quaternion(Ogre::Radian(posdata.rot[0]), Ogre::Vector3::UNIT_X);
 | 
			
		||||
                               Ogre::Quaternion(Ogre::Radian(posdata.rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
 | 
			
		||||
 | 
			
		||||
        MWRender::Animation *anim = mRendering->getAnimation(ptr);
 | 
			
		||||
        if(anim != NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -858,7 +859,7 @@ namespace MWWorld
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z)
 | 
			
		||||
    void World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z)
 | 
			
		||||
    {
 | 
			
		||||
        ESM::Position &pos = ptr.getRefData().getPosition();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -872,27 +873,27 @@ namespace MWWorld
 | 
			
		|||
        bool isPlayer = ptr == mPlayer->getPlayer();
 | 
			
		||||
        bool haveToMove = isPlayer || mWorldScene->isCellActive(*currCell);
 | 
			
		||||
 | 
			
		||||
        if (*currCell != newCell)
 | 
			
		||||
        if (currCell != newCell)
 | 
			
		||||
        {
 | 
			
		||||
            removeContainerScripts(ptr);
 | 
			
		||||
 | 
			
		||||
            if (isPlayer)
 | 
			
		||||
            {
 | 
			
		||||
                if (!newCell.isExterior())
 | 
			
		||||
                    changeToInteriorCell(Misc::StringUtils::lowerCase(newCell.getCell()->mName), pos);
 | 
			
		||||
                if (!newCell->isExterior())
 | 
			
		||||
                    changeToInteriorCell(Misc::StringUtils::lowerCase(newCell->getCell()->mName), pos);
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    int cellX = newCell.getCell()->getGridX();
 | 
			
		||||
                    int cellY = newCell.getCell()->getGridY();
 | 
			
		||||
                    int cellX = newCell->getCell()->getGridX();
 | 
			
		||||
                    int cellY = newCell->getCell()->getGridY();
 | 
			
		||||
                    mWorldScene->changeCell(cellX, cellY, pos, false);
 | 
			
		||||
                }
 | 
			
		||||
                addContainerScripts (getPlayerPtr(), &newCell);
 | 
			
		||||
                addContainerScripts (getPlayerPtr(), newCell);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                if (!mWorldScene->isCellActive(*currCell))
 | 
			
		||||
                    copyObjectToCell(ptr, newCell, pos);
 | 
			
		||||
                else if (!mWorldScene->isCellActive(newCell))
 | 
			
		||||
                    ptr.getClass().copyToCell(ptr, *newCell, pos);
 | 
			
		||||
                else if (!mWorldScene->isCellActive(*newCell))
 | 
			
		||||
                {
 | 
			
		||||
                    mWorldScene->removeObjectFromScene(ptr);
 | 
			
		||||
                    mLocalScripts.remove(ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -900,7 +901,7 @@ namespace MWWorld
 | 
			
		|||
                    haveToMove = false;
 | 
			
		||||
 | 
			
		||||
                    MWWorld::Ptr newPtr = MWWorld::Class::get(ptr)
 | 
			
		||||
                            .copyToCell(ptr, newCell);
 | 
			
		||||
                            .copyToCell(ptr, *newCell);
 | 
			
		||||
                    newPtr.getRefData().setBaseNode(0);
 | 
			
		||||
 | 
			
		||||
                    objectLeftActiveCell(ptr, newPtr);
 | 
			
		||||
| 
						 | 
				
			
			@ -908,7 +909,7 @@ namespace MWWorld
 | 
			
		|||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    MWWorld::Ptr copy =
 | 
			
		||||
                        MWWorld::Class::get(ptr).copyToCell(ptr, newCell, pos);
 | 
			
		||||
                        MWWorld::Class::get(ptr).copyToCell(ptr, *newCell, pos);
 | 
			
		||||
 | 
			
		||||
                    mRendering->updateObjectCell(ptr, copy);
 | 
			
		||||
                    MWBase::Environment::get().getSoundManager()->updatePtr (ptr, copy);
 | 
			
		||||
| 
						 | 
				
			
			@ -923,7 +924,7 @@ namespace MWWorld
 | 
			
		|||
                        mLocalScripts.remove(ptr);
 | 
			
		||||
                        removeContainerScripts (ptr);
 | 
			
		||||
                        mLocalScripts.add(script, copy);
 | 
			
		||||
                        addContainerScripts (copy, &newCell);
 | 
			
		||||
                        addContainerScripts (copy, newCell);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                ptr.getRefData().setCount(0);
 | 
			
		||||
| 
						 | 
				
			
			@ -947,7 +948,7 @@ namespace MWWorld
 | 
			
		|||
            cell = getExterior(cellX, cellY);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        moveObject(ptr, *cell, x, y, z);
 | 
			
		||||
        moveObject(ptr, cell, x, y, z);
 | 
			
		||||
 | 
			
		||||
        return cell != ptr.getCell();
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1041,15 +1042,13 @@ namespace MWWorld
 | 
			
		|||
            while(ptr.getRefData().getLocalRotation().rot[2]<=-fullRotateRad)
 | 
			
		||||
                ptr.getRefData().getLocalRotation().rot[2]+=fullRotateRad;
 | 
			
		||||
 | 
			
		||||
            float *worldRot = ptr.getRefData().getPosition().rot;
 | 
			
		||||
            Ogre::Quaternion worldRotQuat(Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[1]), Ogre::Vector3::NEGATIVE_UNIT_Y)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(ptr.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z));
 | 
			
		||||
 | 
			
		||||
            Ogre::Quaternion worldRotQuat(Ogre::Quaternion(Ogre::Radian(-worldRot[0]), Ogre::Vector3::UNIT_X)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(-worldRot[1]), Ogre::Vector3::UNIT_Y)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(-worldRot[2]), Ogre::Vector3::UNIT_Z));
 | 
			
		||||
 | 
			
		||||
            Ogre::Quaternion rot(Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-x).valueRadians()), Ogre::Vector3::UNIT_X)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-y).valueRadians()), Ogre::Vector3::UNIT_Y)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Radian(Ogre::Degree(-z).valueRadians()), Ogre::Vector3::UNIT_Z));
 | 
			
		||||
            Ogre::Quaternion rot(Ogre::Quaternion(Ogre::Degree(x), Ogre::Vector3::NEGATIVE_UNIT_X)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Degree(y), Ogre::Vector3::NEGATIVE_UNIT_Y)*
 | 
			
		||||
            Ogre::Quaternion(Ogre::Degree(z), Ogre::Vector3::NEGATIVE_UNIT_Z));
 | 
			
		||||
 | 
			
		||||
            ptr.getRefData().getBaseNode()->setOrientation(worldRotQuat*rot);
 | 
			
		||||
            mPhysics->rotateObject(ptr);
 | 
			
		||||
| 
						 | 
				
			
			@ -1080,7 +1079,7 @@ namespace MWWorld
 | 
			
		|||
                pos.z = traced.z;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        moveObject(ptr, *ptr.getCell(), pos.x, pos.y, pos.z);
 | 
			
		||||
        moveObject(ptr, ptr.getCell(), pos.x, pos.y, pos.z);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust)
 | 
			
		||||
| 
						 | 
				
			
			@ -1091,9 +1090,9 @@ namespace MWWorld
 | 
			
		|||
                        adjust);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos)
 | 
			
		||||
    MWWorld::Ptr World::safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos)
 | 
			
		||||
    {
 | 
			
		||||
        return copyObjectToCell(ptr,Cell,pos,false);
 | 
			
		||||
        return copyObjectToCell(ptr,cell,pos,false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const
 | 
			
		||||
| 
						 | 
				
			
			@ -1127,6 +1126,7 @@ namespace MWWorld
 | 
			
		|||
    {
 | 
			
		||||
        processDoors(duration);
 | 
			
		||||
 | 
			
		||||
        moveMagicBolts(duration);
 | 
			
		||||
        moveProjectiles(duration);
 | 
			
		||||
 | 
			
		||||
        const PtrVelocityList &results = mPhysics->applyQueuedMovement(duration);
 | 
			
		||||
| 
						 | 
				
			
			@ -1506,15 +1506,7 @@ namespace MWWorld
 | 
			
		|||
        if (!result.first)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        CellStore* cell;
 | 
			
		||||
        if (isCellExterior())
 | 
			
		||||
        {
 | 
			
		||||
            int cellX, cellY;
 | 
			
		||||
            positionToIndex(result.second[0], result.second[1], cellX, cellY);
 | 
			
		||||
            cell = mCells.getExterior(cellX, cellY);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            cell = getPlayerPtr().getCell();
 | 
			
		||||
        CellStore* cell = getPlayerPtr().getCell();
 | 
			
		||||
 | 
			
		||||
        ESM::Position pos = getPlayerPtr().getRefData().getPosition();
 | 
			
		||||
        pos.pos[0] = result.second[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -1527,7 +1519,7 @@ namespace MWWorld
 | 
			
		|||
        // copy the object and set its count
 | 
			
		||||
        int origCount = object.getRefData().getCount();
 | 
			
		||||
        object.getRefData().setCount(amount);
 | 
			
		||||
        Ptr dropped = copyObjectToCell(object, *cell, pos, true);
 | 
			
		||||
        Ptr dropped = copyObjectToCell(object, cell, pos, true);
 | 
			
		||||
        object.getRefData().setCount(origCount);
 | 
			
		||||
 | 
			
		||||
        // only the player place items in the world, so no need to check actor
 | 
			
		||||
| 
						 | 
				
			
			@ -1548,7 +1540,7 @@ namespace MWWorld
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Ptr World::copyObjectToCell(const Ptr &object, CellStore &cell, ESM::Position pos, bool adjustPos)
 | 
			
		||||
    Ptr World::copyObjectToCell(const Ptr &object, CellStore* cell, ESM::Position pos, bool adjustPos)
 | 
			
		||||
    {
 | 
			
		||||
        if (object.getClass().isActor() || adjustPos)
 | 
			
		||||
        {
 | 
			
		||||
| 
						 | 
				
			
			@ -1560,17 +1552,17 @@ namespace MWWorld
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (cell.isExterior())
 | 
			
		||||
        if (cell->isExterior())
 | 
			
		||||
        {
 | 
			
		||||
            int cellX, cellY;
 | 
			
		||||
            positionToIndex(pos.pos[0], pos.pos[1], cellX, cellY);
 | 
			
		||||
            cell = *mCells.getExterior(cellX, cellY);
 | 
			
		||||
            cell = mCells.getExterior(cellX, cellY);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MWWorld::Ptr dropped =
 | 
			
		||||
            MWWorld::Class::get(object).copyToCell(object, cell, pos);
 | 
			
		||||
            MWWorld::Class::get(object).copyToCell(object, *cell, pos);
 | 
			
		||||
 | 
			
		||||
        if (mWorldScene->isCellActive(cell)) {
 | 
			
		||||
        if (mWorldScene->isCellActive(*cell)) {
 | 
			
		||||
            if (dropped.getRefData().isEnabled()) {
 | 
			
		||||
                mWorldScene->addObjectToScene(dropped);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -1578,7 +1570,7 @@ namespace MWWorld
 | 
			
		|||
            if (!script.empty()) {
 | 
			
		||||
                mLocalScripts.add(script, dropped);
 | 
			
		||||
            }
 | 
			
		||||
            addContainerScripts(dropped, &cell);
 | 
			
		||||
            addContainerScripts(dropped, cell);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return dropped;
 | 
			
		||||
| 
						 | 
				
			
			@ -1608,7 +1600,7 @@ namespace MWWorld
 | 
			
		|||
        // copy the object and set its count
 | 
			
		||||
        int origCount = object.getRefData().getCount();
 | 
			
		||||
        object.getRefData().setCount(amount);
 | 
			
		||||
        Ptr dropped = copyObjectToCell(object, *cell, pos);
 | 
			
		||||
        Ptr dropped = copyObjectToCell(object, cell, pos);
 | 
			
		||||
        object.getRefData().setCount(origCount);
 | 
			
		||||
 | 
			
		||||
        if(actor == mPlayer->getPlayer()) // Only call if dropped by player
 | 
			
		||||
| 
						 | 
				
			
			@ -2143,7 +2135,37 @@ namespace MWWorld
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
 | 
			
		||||
    void World::launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
 | 
			
		||||
                                   const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed)
 | 
			
		||||
    {
 | 
			
		||||
        ProjectileState state;
 | 
			
		||||
        state.mActorHandle = actor.getRefData().getHandle();
 | 
			
		||||
        state.mBow = bow;
 | 
			
		||||
        state.mSpeed = speed;
 | 
			
		||||
 | 
			
		||||
        MWWorld::ManualRef ref(getStore(), projectile.getCellRef().mRefID);
 | 
			
		||||
 | 
			
		||||
        ESM::Position pos;
 | 
			
		||||
        pos.pos[0] = worldPos.x;
 | 
			
		||||
        pos.pos[1] = worldPos.y;
 | 
			
		||||
        pos.pos[2] = worldPos.z;
 | 
			
		||||
 | 
			
		||||
        // Do NOT copy actor rotation! actors use a different rotation order, and this will not produce the same facing direction.
 | 
			
		||||
        Ogre::Matrix3 mat;
 | 
			
		||||
        orient.ToRotationMatrix(mat);
 | 
			
		||||
        Ogre::Radian xr,yr,zr;
 | 
			
		||||
        mat.ToEulerAnglesXYZ(xr, yr, zr);
 | 
			
		||||
        pos.rot[0] = -xr.valueRadians();
 | 
			
		||||
        pos.rot[1] = -yr.valueRadians();
 | 
			
		||||
        pos.rot[2] = -zr.valueRadians();
 | 
			
		||||
 | 
			
		||||
        MWWorld::Ptr ptr = copyObjectToCell(ref.getPtr(), actor.getCell(), pos, false);
 | 
			
		||||
        ptr.getRefData().setCount(1);
 | 
			
		||||
 | 
			
		||||
        mProjectiles[ptr] = state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
 | 
			
		||||
                                   const MWWorld::Ptr& actor, const std::string& sourceName)
 | 
			
		||||
    {
 | 
			
		||||
        std::string projectileModel;
 | 
			
		||||
| 
						 | 
				
			
			@ -2185,13 +2207,23 @@ namespace MWWorld
 | 
			
		|||
        pos.pos[0] = actor.getRefData().getPosition().pos[0];
 | 
			
		||||
        pos.pos[1] = actor.getRefData().getPosition().pos[1];
 | 
			
		||||
        pos.pos[2] = actor.getRefData().getPosition().pos[2] + height;
 | 
			
		||||
        pos.rot[0] = actor.getRefData().getPosition().rot[0];
 | 
			
		||||
        pos.rot[1] = actor.getRefData().getPosition().rot[1];
 | 
			
		||||
        pos.rot[2] = actor.getRefData().getPosition().rot[2];
 | 
			
		||||
        ref.getPtr().getCellRef().mPos = pos;
 | 
			
		||||
        MWWorld::Ptr ptr = copyObjectToCell(ref.getPtr(), *actor.getCell(), pos);
 | 
			
		||||
 | 
			
		||||
        ProjectileState state;
 | 
			
		||||
        // Do NOT copy rotation directly! actors use a different rotation order, and this will not produce the same facing direction.
 | 
			
		||||
        Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[2]), Ogre::Vector3::NEGATIVE_UNIT_Z) *
 | 
			
		||||
                Ogre::Quaternion(Ogre::Radian(actor.getRefData().getPosition().rot[0]), Ogre::Vector3::NEGATIVE_UNIT_X);
 | 
			
		||||
        Ogre::Matrix3 mat;
 | 
			
		||||
        orient.ToRotationMatrix(mat);
 | 
			
		||||
        Ogre::Radian xr,yr,zr;
 | 
			
		||||
        mat.ToEulerAnglesXYZ(xr, yr, zr);
 | 
			
		||||
        pos.rot[0] = -xr.valueRadians();
 | 
			
		||||
        pos.rot[1] = -yr.valueRadians();
 | 
			
		||||
        pos.rot[2] = -zr.valueRadians();
 | 
			
		||||
 | 
			
		||||
        ref.getPtr().getCellRef().mPos = pos;
 | 
			
		||||
        CellStore* cell = actor.getCell();
 | 
			
		||||
        MWWorld::Ptr ptr = copyObjectToCell(ref.getPtr(), cell, pos);
 | 
			
		||||
 | 
			
		||||
        MagicBoltState state;
 | 
			
		||||
        state.mSourceName = sourceName;
 | 
			
		||||
        state.mId = id;
 | 
			
		||||
        state.mActorHandle = actor.getRefData().getHandle();
 | 
			
		||||
| 
						 | 
				
			
			@ -2209,7 +2241,7 @@ namespace MWWorld
 | 
			
		|||
        MWBase::SoundManager *sndMgr = MWBase::Environment::get().getSoundManager();
 | 
			
		||||
        sndMgr->playSound3D(ptr, sound, 1.0f, 1.0f, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop);
 | 
			
		||||
 | 
			
		||||
        mProjectiles[ptr] = state;
 | 
			
		||||
        mMagicBolts[ptr] = state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::moveProjectiles(float duration)
 | 
			
		||||
| 
						 | 
				
			
			@ -2226,13 +2258,100 @@ namespace MWWorld
 | 
			
		|||
 | 
			
		||||
            MWWorld::Ptr ptr = it->first;
 | 
			
		||||
 | 
			
		||||
            Ogre::Quaternion orient = ptr.getRefData().getBaseNode()->getOrientation();
 | 
			
		||||
 | 
			
		||||
            float speed = it->second.mSpeed;
 | 
			
		||||
 | 
			
		||||
            Ogre::Vector3 direction = orient.yAxis();
 | 
			
		||||
            direction.normalise();
 | 
			
		||||
            Ogre::Vector3 pos(ptr.getRefData().getPosition().pos);
 | 
			
		||||
            Ogre::Vector3 newPos = pos + direction * duration * speed;
 | 
			
		||||
 | 
			
		||||
            // Check for impact
 | 
			
		||||
            btVector3 from(pos.x, pos.y, pos.z);
 | 
			
		||||
            btVector3 to(newPos.x, newPos.y, newPos.z);
 | 
			
		||||
            std::vector<std::pair<float, std::string> > collisions = mPhysEngine->rayTest2(from, to);
 | 
			
		||||
            bool hit=false;
 | 
			
		||||
 | 
			
		||||
            // HACK: query against the shape as well, since the ray does not take the volume into account
 | 
			
		||||
            // really, this should be a convex cast, but the whole physics system needs a rewrite
 | 
			
		||||
            std::vector<std::string> col2 = mPhysEngine->getCollisions(ptr.getRefData().getHandle());
 | 
			
		||||
            for (std::vector<std::string>::iterator ci = col2.begin(); ci != col2.end(); ++ci)
 | 
			
		||||
                 collisions.push_back(std::make_pair(0.f,*ci));
 | 
			
		||||
 | 
			
		||||
            for (std::vector<std::pair<float, std::string> >::iterator cIt = collisions.begin(); cIt != collisions.end() && !hit; ++cIt)
 | 
			
		||||
            {
 | 
			
		||||
                MWWorld::Ptr obstacle = searchPtrViaHandle(cIt->second);
 | 
			
		||||
                if (obstacle == ptr)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                MWWorld::Ptr caster = searchPtrViaHandle(it->second.mActorHandle);
 | 
			
		||||
 | 
			
		||||
                // Arrow intersects with player immediately after shooting :/
 | 
			
		||||
                if (obstacle == caster)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                if (caster.isEmpty())
 | 
			
		||||
                    caster = obstacle;
 | 
			
		||||
 | 
			
		||||
                if (obstacle.isEmpty())
 | 
			
		||||
                {
 | 
			
		||||
                    // Terrain
 | 
			
		||||
                }
 | 
			
		||||
                else if (obstacle.getClass().isActor())
 | 
			
		||||
                {
 | 
			
		||||
                    // Fargoth
 | 
			
		||||
                    obstacle.getClass().getCreatureStats(obstacle).setHealth(0);
 | 
			
		||||
                }
 | 
			
		||||
                hit = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (hit)
 | 
			
		||||
            {
 | 
			
		||||
                mProjectiles.erase(it++);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::string handle = ptr.getRefData().getHandle();
 | 
			
		||||
 | 
			
		||||
            moveObject(ptr, newPos.x, newPos.y, newPos.z);
 | 
			
		||||
 | 
			
		||||
            // HACK: Re-fetch Ptrs if necessary, since the cell might have changed
 | 
			
		||||
            if (!ptr.getRefData().getCount())
 | 
			
		||||
            {
 | 
			
		||||
                moved[handle] = it->second;
 | 
			
		||||
                mProjectiles.erase(it++);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                ++it;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // HACK: Re-fetch Ptrs if necessary, since the cell might have changed
 | 
			
		||||
        for (std::map<std::string, ProjectileState>::iterator it = moved.begin(); it != moved.end(); ++it)
 | 
			
		||||
        {
 | 
			
		||||
            MWWorld::Ptr newPtr = searchPtrViaHandle(it->first);
 | 
			
		||||
            if (newPtr.isEmpty()) // The projectile went into an inactive cell and was deleted
 | 
			
		||||
                continue;
 | 
			
		||||
            mProjectiles[getPtrViaHandle(it->first)] = it->second;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::moveMagicBolts(float duration)
 | 
			
		||||
    {
 | 
			
		||||
        std::map<std::string, MagicBoltState> moved;
 | 
			
		||||
        for (std::map<MWWorld::Ptr, MagicBoltState>::iterator it = mMagicBolts.begin(); it != mMagicBolts.end();)
 | 
			
		||||
        {
 | 
			
		||||
            if (!mWorldScene->isCellActive(*it->first.getCell()))
 | 
			
		||||
            {
 | 
			
		||||
                deleteObject(it->first);
 | 
			
		||||
                mMagicBolts.erase(it++);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MWWorld::Ptr ptr = it->first;
 | 
			
		||||
 | 
			
		||||
            Ogre::Vector3 rot(ptr.getRefData().getPosition().rot);
 | 
			
		||||
 | 
			
		||||
            // TODO: Why -rot.z, but not -rot.x? (note: same issue in MovementSolver::move)
 | 
			
		||||
            Ogre::Quaternion orient = Ogre::Quaternion(Ogre::Radian(-rot.z), Ogre::Vector3::UNIT_Z);
 | 
			
		||||
            orient = orient * Ogre::Quaternion(Ogre::Radian(rot.x), Ogre::Vector3::UNIT_X);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            Ogre::Quaternion orient = ptr.getRefData().getBaseNode()->getOrientation();
 | 
			
		||||
            static float fTargetSpellMaxSpeed = getStore().get<ESM::GameSetting>().find("fTargetSpellMaxSpeed")->getFloat();
 | 
			
		||||
            float speed = fTargetSpellMaxSpeed * it->second.mSpeed;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2279,7 +2398,7 @@ namespace MWWorld
 | 
			
		|||
                explodeSpell(Ogre::Vector3(ptr.getRefData().getPosition().pos), ptr, it->second.mEffects, caster, it->second.mId, it->second.mSourceName);
 | 
			
		||||
 | 
			
		||||
                deleteObject(ptr);
 | 
			
		||||
                mProjectiles.erase(it++);
 | 
			
		||||
                mMagicBolts.erase(it++);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2291,29 +2410,29 @@ namespace MWWorld
 | 
			
		|||
            if (!ptr.getRefData().getCount())
 | 
			
		||||
            {
 | 
			
		||||
                moved[handle] = it->second;
 | 
			
		||||
                mProjectiles.erase(it++);
 | 
			
		||||
                mMagicBolts.erase(it++);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                ++it;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // HACK: Re-fetch Ptrs if necessary, since the cell might have changed
 | 
			
		||||
        for (std::map<std::string, ProjectileState>::iterator it = moved.begin(); it != moved.end(); ++it)
 | 
			
		||||
        for (std::map<std::string, MagicBoltState>::iterator it = moved.begin(); it != moved.end(); ++it)
 | 
			
		||||
        {
 | 
			
		||||
            MWWorld::Ptr newPtr = searchPtrViaHandle(it->first);
 | 
			
		||||
            if (newPtr.isEmpty()) // The projectile went into an inactive cell and was deleted
 | 
			
		||||
                continue;
 | 
			
		||||
            mProjectiles[getPtrViaHandle(it->first)] = it->second;
 | 
			
		||||
            mMagicBolts[getPtrViaHandle(it->first)] = it->second;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void World::objectLeftActiveCell(Ptr object, Ptr movedPtr)
 | 
			
		||||
    {
 | 
			
		||||
        // For now, projectiles moved to an inactive cell are just deleted, because there's no reliable way to hold on to the meta information
 | 
			
		||||
        if (mProjectiles.find(object) != mProjectiles.end())
 | 
			
		||||
        {
 | 
			
		||||
        if (mMagicBolts.find(object) != mMagicBolts.end())
 | 
			
		||||
            deleteObject(movedPtr);
 | 
			
		||||
        if (mProjectiles.find(object) != mProjectiles.end())
 | 
			
		||||
            deleteObject(movedPtr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const std::vector<std::string>& World::getContentFiles() const
 | 
			
		||||
| 
						 | 
				
			
			@ -2650,7 +2769,7 @@ namespace MWWorld
 | 
			
		|||
            MWWorld::ManualRef ref(getStore(), selectedCreature, 1);
 | 
			
		||||
            ref.getPtr().getCellRef().mPos = ipos;
 | 
			
		||||
 | 
			
		||||
            safePlaceObject(ref.getPtr(),*cell,ipos);
 | 
			
		||||
            safePlaceObject(ref.getPtr(), cell, ipos);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -90,7 +90,7 @@ namespace MWWorld
 | 
			
		|||
            std::map<MWWorld::Ptr, int> mDoorStates;
 | 
			
		||||
            ///< only holds doors that are currently moving. 0 means closing, 1 opening
 | 
			
		||||
 | 
			
		||||
            struct ProjectileState
 | 
			
		||||
            struct MagicBoltState
 | 
			
		||||
            {
 | 
			
		||||
                // Id of spell or enchantment to apply when it hits
 | 
			
		||||
                std::string mId;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,6 +108,17 @@ namespace MWWorld
 | 
			
		|||
                bool mStack;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            struct ProjectileState
 | 
			
		||||
            {
 | 
			
		||||
                // Actor who shot this projectile
 | 
			
		||||
                std::string mActorHandle;
 | 
			
		||||
 | 
			
		||||
                MWWorld::Ptr mBow; // bow or crossbow the projectile was fired from
 | 
			
		||||
 | 
			
		||||
                float mSpeed;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            std::map<MWWorld::Ptr, MagicBoltState> mMagicBolts;
 | 
			
		||||
            std::map<MWWorld::Ptr, ProjectileState> mProjectiles;
 | 
			
		||||
            void updateWeather(float duration);
 | 
			
		||||
            int getDaysPerMonth (int month) const;
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +128,7 @@ namespace MWWorld
 | 
			
		|||
            bool moveObjectImp (const Ptr& ptr, float x, float y, float z);
 | 
			
		||||
            ///< @return true if the active cell (cell player is in) changed
 | 
			
		||||
 | 
			
		||||
            Ptr copyObjectToCell(const Ptr &ptr, CellStore &cell, ESM::Position pos, bool adjustPos=true);
 | 
			
		||||
            Ptr copyObjectToCell(const Ptr &ptr, CellStore* cell, ESM::Position pos, bool adjustPos=true);
 | 
			
		||||
 | 
			
		||||
            void updateWindowManager ();
 | 
			
		||||
            void performUpdateSceneQueries ();
 | 
			
		||||
| 
						 | 
				
			
			@ -134,6 +145,7 @@ namespace MWWorld
 | 
			
		|||
            void processDoors(float duration);
 | 
			
		||||
            ///< Run physics simulation and modify \a world accordingly.
 | 
			
		||||
 | 
			
		||||
            void moveMagicBolts(float duration);
 | 
			
		||||
            void moveProjectiles(float duration);
 | 
			
		||||
 | 
			
		||||
            void doPhysics(float duration);
 | 
			
		||||
| 
						 | 
				
			
			@ -341,7 +353,7 @@ namespace MWWorld
 | 
			
		|||
            virtual void deleteObject (const Ptr& ptr);
 | 
			
		||||
 | 
			
		||||
            virtual void moveObject (const Ptr& ptr, float x, float y, float z);
 | 
			
		||||
            virtual void moveObject (const Ptr& ptr, CellStore &newCell, float x, float y, float z);
 | 
			
		||||
            virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z);
 | 
			
		||||
 | 
			
		||||
            virtual void scaleObject (const Ptr& ptr, float scale);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -351,7 +363,7 @@ namespace MWWorld
 | 
			
		|||
 | 
			
		||||
            virtual void localRotateObject (const Ptr& ptr, float x, float y, float z);
 | 
			
		||||
 | 
			
		||||
            virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos);
 | 
			
		||||
            virtual MWWorld::Ptr safePlaceObject(const MWWorld::Ptr& ptr, MWWorld::CellStore* cell, ESM::Position pos);
 | 
			
		||||
            ///< place an object in a "safe" location (ie not in the void, etc). Makes a copy of the Ptr.
 | 
			
		||||
 | 
			
		||||
            virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false)
 | 
			
		||||
| 
						 | 
				
			
			@ -552,8 +564,10 @@ namespace MWWorld
 | 
			
		|||
             */
 | 
			
		||||
            virtual void castSpell (const MWWorld::Ptr& actor);
 | 
			
		||||
 | 
			
		||||
            virtual void launchProjectile (const std::string& id, bool stack, const ESM::EffectList& effects,
 | 
			
		||||
            virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
 | 
			
		||||
                                           const MWWorld::Ptr& actor, const std::string& sourceName);
 | 
			
		||||
            virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
 | 
			
		||||
                                           const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            virtual const std::vector<std::string>& getContentFiles() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -597,6 +597,8 @@ namespace Physic
 | 
			
		|||
    std::vector<std::string> PhysicEngine::getCollisions(const std::string& name)
 | 
			
		||||
    {
 | 
			
		||||
        RigidBody* body = getRigidBody(name);
 | 
			
		||||
        if (!body) // fall back to raycasting body if there is no collision body
 | 
			
		||||
            body = getRigidBody(name, true);
 | 
			
		||||
        ContactTestResultCallback callback;
 | 
			
		||||
        dynamicsWorld->contactTest(body, callback);
 | 
			
		||||
        return callback.mResult;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue