diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a83d6906f4..9d432c5b6a 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -142,6 +142,9 @@ namespace MWBase virtual MWWorld::Ptr getPtrViaHandle (const std::string& handle) = 0; ///< Return a pointer to a liveCellRef with the given Ogre handle. + virtual void + copyObjectToCell(const MWWorld::Ptr &ptr, MWWorld::CellStore &cell, const ESM::Position &pos) = 0; + /// \todo enable reference in the OGRE scene virtual void enable (const MWWorld::Ptr& ptr) = 0; @@ -204,6 +207,9 @@ namespace MWBase virtual void rotateObject(const MWWorld::Ptr& ptr,float x,float y,float z, bool adjust = false) = 0; + virtual void 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). Makes a copy of the Ptr. + virtual void indexToPosition (int cellX, int cellY, float &x, float &y, bool centre = false) const = 0; ///< Convert cell numbers to position. diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 8052c6a082..d58045a0ab 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -31,7 +31,7 @@ op 0x2000e: PCGetRank implicit op 0x2000f: PCGetRank explicit op 0x20010: AiWander op 0x20011: AiWander, explicit reference -opcodes 0x20012-0x3ffff unused +op s 0x20012-0x3ffff unused Segment 4: (not implemented yet) @@ -187,4 +187,20 @@ op 0x200018C: GetLevel op 0x200018D: GetLevel, explicit reference op 0x200018E: SetLevel op 0x200018F: SetLevel, explicit reference -opcodes 0x200018F-0x3ffffff unused +op 0x2000190: GetPos +op 0x2000191: GetPosExplicit +op 0x2000192: SetPos +op 0x2000193: SetPosExplicit +op 0x2000194: GetStartingPos +op 0x2000195: GetStartingPosExplicit +op 0x2000196: Position +op 0x2000197: Position Explicit +op 0x2000198: PositionCell +op 0x2000199: PositionCell Explicit +op 0x200019a: PlaceItemCell +op 0x200019b: PlaceItem +op 0x200019c: PlaceAtPc +op 0x200019d: PlaceAtMe +op 0x200019e: PlaceAtMe Explicit +opcodes 0x200019f-0x3ffffff unused + diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 6f906343cb..4ce1c7cdfe 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -16,6 +16,13 @@ #include "ref.hpp" #include "OgreSceneNode.h" + +#include "../mwworld/player.hpp" +#include +#include "../mwworld/manualref.hpp" + +#include "OgreMath.h" + namespace MWScript { namespace Transformation @@ -141,6 +148,368 @@ namespace MWScript } }; + template + class OpGetPos : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + if(axis == "x") + { + runtime.push(ptr.getRefData().getPosition().pos[0]); + } + else if(axis == "y") + { + runtime.push(ptr.getRefData().getPosition().pos[1]); + } + else if(axis == "z") + { + runtime.push(ptr.getRefData().getPosition().pos[2]); + } + } + }; + + template + class OpSetPos : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + Interpreter::Type_Float pos = runtime[0].mFloat; + runtime.pop(); + + float ax = ptr.getRefData().getPosition().pos[0]; + float ay = ptr.getRefData().getPosition().pos[1]; + float az = ptr.getRefData().getPosition().pos[2]; + + + if(axis == "x") + { + MWBase::Environment::get().getWorld()->moveObject(ptr,pos,ay,az); + } + else if(axis == "y") + { + MWBase::Environment::get().getWorld()->moveObject(ptr,ax,pos,az); + } + else if(axis == "z") + { + MWBase::Environment::get().getWorld()->moveObject(ptr,ax,ay,pos); + } + } + }; + + template + class OpGetStartingPos : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + std::string axis = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + if(axis == "x") + { + runtime.push(ptr.getCellRef().pos.pos[0]); + } + else if(axis == "y") + { + runtime.push(ptr.getCellRef().pos.pos[1]); + } + else if(axis == "z") + { + runtime.push(ptr.getCellRef().pos.pos[2]); + } + } + }; + + template + class OpPositionCell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::CellStore* store = 0; + try + { + store = MWBase::Environment::get().getWorld()->getInterior(cellID); + } + catch(std::exception &e) + { + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + if(cell) + { + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + } + } + if(store) + { + 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 + { + ax = ax/60.; + ay = ay/60.; + zRot = zRot/60.; + } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + } + else + { + throw std::runtime_error ("unknown cell"); + } + } + }; + + template + class OpPosition : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + 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); + 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 + { + ax = ax/60.; + ay = ay/60.; + zRot = zRot/60.; + } + MWBase::Environment::get().getWorld()->rotateObject(ptr,ax,ay,zRot); + } + }; + + template + class OpPlaceItemCell : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + //MWWorld::Ptr ptr = R()(runtime); + + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + std::string cellID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + + MWWorld::CellStore* store = 0; + try + { + store = MWBase::Environment::get().getWorld()->getInterior(cellID); + } + catch(std::exception &e) + { + const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); + if(cell) + { + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + } + } + if(store) + { + ESM::Position pos; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; + pos.rot[0] = pos.rot[1] = 0; + pos.rot[2] = zRot; + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().pos = pos; + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,pos); + } + else + { + throw std::runtime_error ("unknown cell"); + } + } + }; + + template + class OpPlaceItem : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + //MWWorld::Ptr ptr = R()(runtime); + + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Float x = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float y = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float z = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Float zRot = runtime[0].mFloat; + runtime.pop(); + + MWWorld::CellStore* store = 0; + int cx,cy; + MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); + store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); + if(store) + { + ESM::Position pos; + pos.pos[0] = x; + pos.pos[1] = y; + pos.pos[2] = z; + pos.rot[0] = pos.rot[1] = 0; + pos.rot[2] = zRot; + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().pos = pos; + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,pos); + } + else + { + throw std::runtime_error ("unknown cell"); + } + } + }; + + template + class OpPlaceAtPc : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + Interpreter::Type_Float distance = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Integer direction = runtime[0].mInteger; + runtime.pop(); + + ESM::Position ipos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); + Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); + Ogre::Quaternion rot(Ogre::Radian(ipos.rot[2]), Ogre::Vector3::UNIT_Z); + if(direction == 0) pos = pos + distance*rot.yAxis(); + else if(direction == 1) pos = pos - distance*rot.yAxis(); + else if(direction == 2) pos = pos - distance*rot.xAxis(); + else if(direction == 3) pos = pos + distance*rot.xAxis(); + else throw std::runtime_error ("direction must be 0,1,2 or 3"); + + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + MWWorld::CellStore* store = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().pos = ipos; + ref.getPtr().getRefData().setCount(count); + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); + } + }; + + template + class OpPlaceAtMe : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr me = R()(runtime); + + std::string itemID = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + Interpreter::Type_Integer count = runtime[0].mInteger; + runtime.pop(); + Interpreter::Type_Float distance = runtime[0].mFloat; + runtime.pop(); + Interpreter::Type_Integer direction = runtime[0].mInteger; + runtime.pop(); + + ESM::Position ipos = me.getRefData().getPosition(); + Ogre::Vector3 pos(ipos.pos[0],ipos.pos[1],ipos.pos[2]); + Ogre::Quaternion rot(Ogre::Radian(ipos.rot[2]), Ogre::Vector3::UNIT_Z); + if(direction == 0) pos = pos + distance*rot.yAxis(); + else if(direction == 1) pos = pos - distance*rot.yAxis(); + else if(direction == 2) pos = pos - distance*rot.xAxis(); + else if(direction == 3) pos = pos + distance*rot.xAxis(); + else throw std::runtime_error ("direction must be 0,1,2 or 3"); + + ipos.pos[0] = pos.x; + ipos.pos[1] = pos.y; + ipos.pos[2] = pos.z; + ipos.rot[0] = 0; + ipos.rot[1] = 0; + ipos.rot[2] = 0; + + MWWorld::CellStore* store = me.getCell(); + MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(),itemID); + ref.getPtr().getCellRef().pos = ipos; + ref.getPtr().getRefData().setCount(count); + MWBase::Environment::get().getWorld()->safePlaceObject(ref.getPtr(),*store,ipos); + + } + }; + const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -149,16 +518,38 @@ namespace MWScript const int opcodeGetScaleExplicit = 0x2000169; const int opcodeGetAngle = 0x200016a; const int opcodeGetAngleExplicit = 0x200016b; - const int opcodeGetStartingAngle = 0x2000172; - const int opcodeGetStartingAngleExplicit = 0x2000173; + const int opcodeGetPos = 0x2000190; + const int opcodeGetPosExplicit = 0x2000191; + const int opcodeSetPos = 0x2000192; + const int opcodeSetPosExplicit = 0x2000193; + const int opcodeGetStartingPos = 0x2000194; + const int opcodeGetStartingPosExplicit = 0x2000195; + const int opcodePosition = 0x2000196; + const int opcodePositionExplicit = 0x2000197; + const int opcodePositionCell = 0x2000198; + const int opcodePositionCellExplicit = 0x2000199; + + const int opcodePlaceItemCell = 0x200019a; + const int opcodePlaceItem = 0x200019b; + const int opcodePlaceAtPc = 0x200019c; + const int opcodePlaceAtMe = 0x200019d; + const int opcodePlaceAtMeExplicit = 0x200019e; void registerExtensions (Compiler::Extensions& extensions) { extensions.registerInstruction("setscale","f",opcodeSetScale,opcodeSetScaleExplicit); extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit); - extensions.registerInstruction("setangle","cf",opcodeSetAngle,opcodeSetAngleExplicit); - extensions.registerFunction("getangle",'f',"c",opcodeGetAngle,opcodeGetAngleExplicit); - extensions.registerFunction("getstartingangle",'f',"c",opcodeGetStartingAngle,opcodeGetStartingAngleExplicit); + extensions.registerInstruction("setangle","Sf",opcodeSetAngle,opcodeSetAngleExplicit); + extensions.registerFunction("getangle",'f',"S",opcodeGetAngle,opcodeGetAngleExplicit); + extensions.registerInstruction("setpos","cf",opcodeSetPos,opcodeSetPosExplicit); + extensions.registerFunction("getpos",'f',"c",opcodeGetPos,opcodeGetPosExplicit); + extensions.registerFunction("getstartingpos",'f',"c",opcodeGetStartingPos,opcodeGetStartingPosExplicit); + extensions.registerInstruction("position","ffff",opcodePosition,opcodePositionExplicit); + extensions.registerInstruction("positioncell","ffffS",opcodePositionCell,opcodePositionCellExplicit); + extensions.registerInstruction("placeitemcell","ccffff",opcodePlaceItemCell); + extensions.registerInstruction("placeitem","cffff",opcodePlaceItem); + extensions.registerInstruction("placeatpc","clfl",opcodePlaceAtPc); + extensions.registerInstruction("placeatme","clfl",opcodePlaceAtMe,opcodePlaceAtMeExplicit); } void installOpcodes (Interpreter::Interpreter& interpreter) @@ -171,8 +562,21 @@ namespace MWScript interpreter.installSegment5(opcodeGetScaleExplicit,new OpGetScale); interpreter.installSegment5(opcodeGetAngle,new OpGetAngle); interpreter.installSegment5(opcodeGetAngleExplicit,new OpGetAngle); - interpreter.installSegment5(opcodeGetStartingAngle,new OpGetStartingAngle); - interpreter.installSegment5(opcodeGetStartingAngleExplicit,new OpGetStartingAngle); + interpreter.installSegment5(opcodeGetPos,new OpGetPos); + interpreter.installSegment5(opcodeGetPosExplicit,new OpGetPos); + interpreter.installSegment5(opcodeSetPos,new OpSetPos); + interpreter.installSegment5(opcodeSetPosExplicit,new OpSetPos); + interpreter.installSegment5(opcodeGetStartingPos,new OpGetStartingPos); + interpreter.installSegment5(opcodeGetStartingPosExplicit,new OpGetStartingPos); + interpreter.installSegment5(opcodePosition,new OpPosition); + interpreter.installSegment5(opcodePositionExplicit,new OpPosition); + interpreter.installSegment5(opcodePositionCell,new OpPositionCell); + interpreter.installSegment5(opcodePositionCellExplicit,new OpPositionCell); + interpreter.installSegment5(opcodePlaceItemCell,new OpPlaceItemCell); + interpreter.installSegment5(opcodePlaceItem,new OpPlaceItem); + interpreter.installSegment5(opcodePlaceAtPc,new OpPlaceAtPc); + interpreter.installSegment5(opcodePlaceAtMe,new OpPlaceAtMe); + interpreter.installSegment5(opcodePlaceAtMeExplicit,new OpPlaceAtMe); } } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6c92678365..8316116186 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -541,6 +541,16 @@ namespace MWWorld } } + std::string toLower (const std::string& name) + { + std::string lowerCase; + + std::transform (name.begin(), name.end(), std::back_inserter (lowerCase), + (int(*)(int)) std::tolower); + + return lowerCase; + } + void World::moveObject(const Ptr &ptr, CellStore &newCell, float x, float y, float z) { ESM::Position &pos = ptr.getRefData().getPosition(); @@ -550,11 +560,10 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; - if (*currCell != newCell) { if (isPlayer) { if (!newCell.isExterior()) { - changeToInteriorCell(newCell.cell->name, pos); + changeToInteriorCell(toLower(newCell.cell->name), pos); } else { int cellX = newCell.cell->data.gridX; int cellY = newCell.cell->data.gridY; @@ -647,6 +656,11 @@ namespace MWWorld } } + void World::safePlaceObject(const MWWorld::Ptr& ptr,MWWorld::CellStore &Cell,ESM::Position pos) + { + copyObjectToCell(ptr,Cell,pos); + } + void World::indexToPosition (int cellX, int cellY, float &x, float &y, bool centre) const { const int cellSize = 8192; diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 96e6ae3f81..d48a0ec814 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -223,6 +223,9 @@ namespace MWWorld /// \param adjust indicates rotation should be set or adjusted virtual void rotateObject (const Ptr& ptr,float x,float y,float z, bool adjust = false); + virtual void 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) const; ///< Convert cell numbers to position.