2018-08-14 23:05:43 +04:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2015-06-03 23:04:35 +02:00
|
|
|
|
2015-11-20 21:57:04 +01:00
|
|
|
#include <components/sceneutil/positionattitudetransform.hpp>
|
2012-09-18 10:49:51 +02:00
|
|
|
|
2022-01-22 15:58:41 +01:00
|
|
|
#include <components/esm3/loadcell.hpp>
|
2012-07-09 18:47:59 +02:00
|
|
|
|
2013-08-06 20:38:41 -04:00
|
|
|
#include <components/compiler/opcodes.hpp>
|
2012-07-09 18:47:59 +02:00
|
|
|
|
|
|
|
#include <components/interpreter/interpreter.hpp>
|
|
|
|
#include <components/interpreter/opcodes.hpp>
|
2022-09-22 21:26:05 +03:00
|
|
|
#include <components/interpreter/runtime.hpp>
|
2012-07-09 18:47:59 +02:00
|
|
|
|
|
|
|
#include "../mwbase/environment.hpp"
|
2015-02-09 17:45:48 +01:00
|
|
|
#include "../mwbase/world.hpp"
|
2012-07-09 18:47:59 +02:00
|
|
|
|
2015-02-09 15:01:49 +01:00
|
|
|
#include "../mwworld/cellstore.hpp"
|
2012-07-09 18:47:59 +02:00
|
|
|
#include "../mwworld/class.hpp"
|
2012-09-18 10:49:51 +02:00
|
|
|
#include "../mwworld/manualref.hpp"
|
2014-01-08 18:39:44 +01:00
|
|
|
#include "../mwworld/player.hpp"
|
2022-11-06 20:06:45 +01:00
|
|
|
#include "../mwworld/scene.hpp"
|
2022-12-06 00:11:19 +01:00
|
|
|
#include "../mwworld/worldmodel.hpp"
|
2012-07-09 18:47:59 +02:00
|
|
|
|
2015-08-21 21:12:39 +12:00
|
|
|
#include "../mwmechanics/actorutil.hpp"
|
2023-05-13 15:26:39 +02:00
|
|
|
#include "../mwmechanics/creaturestats.hpp"
|
2015-08-21 21:12:39 +12:00
|
|
|
|
2012-07-09 18:47:59 +02:00
|
|
|
#include "interpretercontext.hpp"
|
|
|
|
#include "ref.hpp"
|
|
|
|
|
|
|
|
namespace MWScript
|
|
|
|
{
|
|
|
|
namespace Transformation
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
void moveStandingActors(const MWWorld::Ptr& ptr, const osg::Vec3f& diff)
|
2018-08-25 10:34:33 +04:00
|
|
|
{
|
|
|
|
std::vector<MWWorld::Ptr> actors;
|
2022-09-22 21:26:05 +03:00
|
|
|
MWBase::Environment::get().getWorld()->getActorsStandingOn(ptr, actors);
|
2018-08-25 10:34:33 +04:00
|
|
|
for (auto& actor : actors)
|
In 0.46, SetPos was setting position of actors before physics simulation, and from this position movement was simulated. This changed with async physics merging, and at the same time problems started, mostly with abot's scenic travel.
Skipping the simulation, switching off collisions, and other approaches were not correct as they either broke some mods, or some core mechanics of the engine such as teleportation or waterwalking. As it turns out, the way to go is to simply do _nothing_ (modulo some gymnastics to account for the 1 frame difference in case of async).
Scripted movement and the unstucking logic tends to collide. Early out of unstuck in case the actor doesn't attempt to move. This means there is no AI package for NPC, which are the case for some boats and striders, or the player is content with their position.
2023-03-16 21:33:36 +01:00
|
|
|
MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false);
|
2018-08-25 10:34:33 +04:00
|
|
|
}
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2020-05-13 21:17:08 +02:00
|
|
|
class OpGetDistance : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr from = R()(runtime, !R::implicit);
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
ESM::RefId name = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.pop();
|
2020-05-13 21:17:08 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (from.isEmpty())
|
2020-05-13 21:17:08 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string error = "Missing implicit ref";
|
|
|
|
runtime.getContext().report(error);
|
|
|
|
Log(Debug::Error) << error;
|
|
|
|
runtime.push(0.f);
|
|
|
|
return;
|
|
|
|
}
|
2021-03-11 20:37:38 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (from.getContainerStore()) // is the object contained?
|
|
|
|
{
|
|
|
|
MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(from);
|
2020-05-13 21:17:08 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (!container.isEmpty())
|
|
|
|
from = container;
|
|
|
|
else
|
2020-05-22 14:04:26 +03:00
|
|
|
{
|
2023-02-20 23:11:18 +01:00
|
|
|
const std::string error
|
|
|
|
= "Failed to find the container of object " + from.getCellRef().getRefId().toDebugString();
|
2020-05-22 14:04:26 +03:00
|
|
|
runtime.getContext().report(error);
|
|
|
|
Log(Debug::Error) << error;
|
|
|
|
runtime.push(0.f);
|
|
|
|
return;
|
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2020-05-13 21:17:08 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
const MWWorld::Ptr to = MWBase::Environment::get().getWorld()->searchPtr(name, false);
|
|
|
|
if (to.isEmpty())
|
|
|
|
{
|
2023-02-20 23:11:18 +01:00
|
|
|
const std::string error = "Failed to find an instance of object " + name.toDebugString();
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.getContext().report(error);
|
|
|
|
Log(Debug::Error) << error;
|
|
|
|
runtime.push(0.f);
|
|
|
|
return;
|
|
|
|
}
|
2020-05-13 21:17:08 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
float distance;
|
|
|
|
// If the objects are in different worldspaces, return a large value (just like vanilla)
|
|
|
|
if (!to.isInCell() || !from.isInCell()
|
2023-02-20 22:33:35 +01:00
|
|
|
|| to.getCell()->getCell()->getWorldSpace() != from.getCell()->getCell()->getWorldSpace())
|
2022-09-22 21:26:05 +03:00
|
|
|
distance = std::numeric_limits<float>::max();
|
|
|
|
else
|
|
|
|
{
|
|
|
|
double diff[3];
|
2020-05-13 21:17:08 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
const float* const pos1 = to.getRefData().getPosition().pos;
|
|
|
|
const float* const pos2 = from.getRefData().getPosition().pos;
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
diff[i] = pos1[i] - pos2[i];
|
2020-05-13 21:17:08 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
distance = static_cast<float>(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]));
|
2020-05-13 21:17:08 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
|
|
|
|
runtime.push(distance);
|
|
|
|
}
|
2020-05-13 21:17:08 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2012-07-09 18:47:59 +02:00
|
|
|
class OpSetScale : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2012-07-09 18:47:59 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
Interpreter::Type_Float scale = runtime[0].mFloat;
|
|
|
|
runtime.pop();
|
2012-07-09 18:47:59 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, scale);
|
|
|
|
}
|
2012-07-09 18:47:59 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2012-07-09 19:28:44 +02:00
|
|
|
class OpGetScale : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
|
|
|
runtime.push(ptr.getCellRef().getScale());
|
|
|
|
}
|
2012-07-09 19:28:44 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2012-11-27 06:54:13 +01:00
|
|
|
class OpModScale : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2012-11-27 06:54:13 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
Interpreter::Type_Float scale = runtime[0].mFloat;
|
|
|
|
runtime.pop();
|
2012-11-27 06:54:13 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
// add the parameter to the object's scale.
|
|
|
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale() + scale);
|
|
|
|
}
|
2012-11-27 06:54:13 +01:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2012-07-09 18:47:59 +02:00
|
|
|
class OpSetAngle : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
|
|
|
|
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
|
|
|
Interpreter::Type_Float angle = osg::DegreesToRadians(runtime[0].mFloat);
|
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
float ax = ptr.getRefData().getPosition().rot[0];
|
|
|
|
float ay = ptr.getRefData().getPosition().rot[1];
|
|
|
|
float az = ptr.getRefData().getPosition().rot[2];
|
|
|
|
|
|
|
|
// XYZ axis use the inverse (XYZ) rotation order like vanilla SetAngle.
|
|
|
|
// UWV axis use the standard (ZYX) rotation order like TESCS/OpenMW-CS and the rest of the game.
|
|
|
|
if (axis == "x")
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, osg::Vec3f(angle, ay, az), MWBase::RotationFlag_inverseOrder);
|
|
|
|
else if (axis == "y")
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, osg::Vec3f(ax, angle, az), MWBase::RotationFlag_inverseOrder);
|
|
|
|
else if (axis == "z")
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, osg::Vec3f(ax, ay, angle), MWBase::RotationFlag_inverseOrder);
|
|
|
|
else if (axis == "u")
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, osg::Vec3f(angle, ay, az), MWBase::RotationFlag_none);
|
|
|
|
else if (axis == "w")
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, osg::Vec3f(ax, angle, az), MWBase::RotationFlag_none);
|
|
|
|
else if (axis == "v")
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, osg::Vec3f(ax, ay, angle), MWBase::RotationFlag_none);
|
|
|
|
}
|
2012-07-09 18:47:59 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2012-08-01 12:21:42 +02:00
|
|
|
class OpGetStartingAngle : public Interpreter::Opcode0
|
2012-07-09 19:28:44 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2012-07-09 19:28:44 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
2012-07-09 19:28:44 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
float ret = 0.f;
|
|
|
|
if (!axis.empty())
|
|
|
|
{
|
|
|
|
if (axis[0] == 'x')
|
|
|
|
{
|
|
|
|
ret = osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[0]);
|
|
|
|
}
|
|
|
|
else if (axis[0] == 'y')
|
2012-07-09 19:28:44 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[1]);
|
|
|
|
}
|
|
|
|
else if (axis[0] == 'z')
|
|
|
|
{
|
|
|
|
ret = osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[2]);
|
2012-07-09 19:28:44 +02:00
|
|
|
}
|
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.push(ret);
|
|
|
|
}
|
2012-07-09 19:28:44 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2012-08-01 12:21:42 +02:00
|
|
|
class OpGetAngle : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2012-08-01 12:21:42 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
2012-08-02 14:57:35 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
float ret = 0.f;
|
|
|
|
if (!axis.empty())
|
|
|
|
{
|
|
|
|
if (axis[0] == 'x')
|
2012-08-01 12:21:42 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]);
|
2012-08-01 12:21:42 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
else if (axis[0] == 'y')
|
2012-08-03 18:14:05 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]);
|
|
|
|
}
|
|
|
|
else if (axis[0] == 'z')
|
|
|
|
{
|
|
|
|
ret = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2]);
|
2012-08-03 18:14:05 +02:00
|
|
|
}
|
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.push(ret);
|
|
|
|
}
|
2012-08-03 18:14:05 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
|
|
|
class OpGetPos : public Interpreter::Opcode0
|
2012-08-03 18:14:05 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2022-04-30 16:45:45 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
2017-12-13 10:53:23 +04:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
float ret = 0.f;
|
|
|
|
if (!axis.empty())
|
|
|
|
{
|
|
|
|
if (axis[0] == 'x')
|
2012-08-03 18:14:05 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = ptr.getRefData().getPosition().pos[0];
|
2012-08-03 18:14:05 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
else if (axis[0] == 'y')
|
2012-08-03 18:14:05 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = ptr.getRefData().getPosition().pos[1];
|
2012-08-03 18:14:05 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
else if (axis[0] == 'z')
|
2019-05-02 20:49:40 +03:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = ptr.getRefData().getPosition().pos[2];
|
2019-05-02 20:49:40 +03:00
|
|
|
}
|
2012-08-03 18:14:05 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.push(ret);
|
|
|
|
}
|
2012-08-03 18:14:05 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
|
|
|
class OpSetPos : public Interpreter::Opcode0
|
2012-08-03 18:20:51 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2012-08-03 18:20:51 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
|
|
|
Interpreter::Type_Float pos = runtime[0].mFloat;
|
|
|
|
runtime.pop();
|
2012-08-03 18:20:51 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (!ptr.isInCell())
|
|
|
|
return;
|
2012-08-03 18:20:51 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
// Note: SetPos does not skip weather transitions in vanilla engine, so we do not call
|
|
|
|
// setTeleported(true) here.
|
|
|
|
|
|
|
|
const auto curPos = ptr.getRefData().getPosition().asVec3();
|
|
|
|
auto newPos = curPos;
|
|
|
|
if (axis == "x")
|
|
|
|
{
|
|
|
|
newPos[0] = pos;
|
|
|
|
}
|
|
|
|
else if (axis == "y")
|
|
|
|
{
|
|
|
|
newPos[1] = pos;
|
|
|
|
}
|
|
|
|
else if (axis == "z")
|
|
|
|
{
|
|
|
|
// We should not place actors under ground
|
|
|
|
if (ptr.getClass().isActor())
|
2012-08-03 18:20:51 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
float terrainHeight = -std::numeric_limits<float>::max();
|
|
|
|
if (ptr.getCell()->isExterior())
|
|
|
|
terrainHeight = MWBase::Environment::get().getWorld()->getTerrainHeightAt(curPos);
|
|
|
|
|
|
|
|
if (pos < terrainHeight)
|
|
|
|
pos = terrainHeight;
|
2012-08-03 18:20:51 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
|
|
|
|
newPos[2] = pos;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return;
|
2012-08-03 18:20:51 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
|
|
|
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
|
In 0.46, SetPos was setting position of actors before physics simulation, and from this position movement was simulated. This changed with async physics merging, and at the same time problems started, mostly with abot's scenic travel.
Skipping the simulation, switching off collisions, and other approaches were not correct as they either broke some mods, or some core mechanics of the engine such as teleportation or waterwalking. As it turns out, the way to go is to simply do _nothing_ (modulo some gymnastics to account for the 1 frame difference in case of async).
Scripted movement and the unstucking logic tends to collide. Early out of unstuck in case the actor doesn't attempt to move. This means there is no AI package for NPC, which are the case for some boats and striders, or the player is content with their position.
2023-03-16 21:33:36 +01:00
|
|
|
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, newPos - curPos, true));
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2012-08-03 18:20:51 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
|
|
|
class OpGetStartingPos : public Interpreter::Opcode0
|
2012-08-09 23:45:06 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2022-04-30 16:45:45 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
2022-04-30 16:45:45 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
float ret = 0.f;
|
|
|
|
if (!axis.empty())
|
|
|
|
{
|
|
|
|
if (axis[0] == 'x')
|
2012-08-11 19:16:00 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = ptr.getCellRef().getPosition().pos[0];
|
2012-08-11 19:16:00 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
else if (axis[0] == 'y')
|
2012-08-11 09:52:49 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = ptr.getCellRef().getPosition().pos[1];
|
2012-08-11 09:52:49 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
else if (axis[0] == 'z')
|
2012-08-09 23:45:06 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
ret = ptr.getCellRef().getPosition().pos[2];
|
2012-08-18 10:50:58 +02:00
|
|
|
}
|
2012-08-09 23:45:06 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.push(ret);
|
|
|
|
}
|
2012-08-09 23:45:06 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
|
|
|
class OpPositionCell : public Interpreter::Opcode0
|
2012-08-05 16:44:56 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
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();
|
2023-01-19 17:31:45 +01:00
|
|
|
std::string_view cellID = runtime.getStringLiteral(runtime[0].mInteger);
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
if (ptr.getContainerStore())
|
|
|
|
return;
|
|
|
|
|
|
|
|
bool isPlayer = ptr == MWMechanics::getPlayer();
|
2022-10-31 12:29:29 +01:00
|
|
|
auto world = MWBase::Environment::get().getWorld();
|
2022-11-06 20:06:45 +01:00
|
|
|
auto worldModel = MWBase::Environment::get().getWorldModel();
|
2023-05-13 15:26:39 +02:00
|
|
|
if (ptr.getClass().isActor())
|
|
|
|
ptr.getClass().getCreatureStats(ptr).setTeleported(true);
|
2022-09-22 21:26:05 +03:00
|
|
|
if (isPlayer)
|
2022-10-31 12:29:29 +01:00
|
|
|
world->getPlayer().setTeleported(true);
|
2022-04-30 16:45:45 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
MWWorld::CellStore* store = nullptr;
|
|
|
|
try
|
|
|
|
{
|
2023-04-20 15:55:40 +02:00
|
|
|
store = &worldModel->getCell(cellID);
|
2023-02-06 16:36:45 +01:00
|
|
|
if (store->isExterior())
|
|
|
|
{
|
2023-05-12 13:24:59 +02:00
|
|
|
const ESM::ExteriorCellLocation cellIndex
|
2023-05-27 01:18:17 +02:00
|
|
|
= ESM::positionToExteriorCellLocation(x, y, store->getCell()->getWorldSpace());
|
2023-05-12 12:04:04 +02:00
|
|
|
store = &worldModel->getExterior(cellIndex);
|
2023-02-06 16:36:45 +01:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
// cell not found, move to exterior instead if moving the player (vanilla PositionCell
|
|
|
|
// compatibility)
|
2023-01-19 17:31:45 +01:00
|
|
|
std::string error = "Warning: PositionCell: unknown interior cell (" + std::string(cellID) + ")";
|
2022-12-24 01:56:27 +01:00
|
|
|
if (isPlayer)
|
|
|
|
error += ", moving to exterior instead";
|
|
|
|
runtime.getContext().report(error);
|
|
|
|
Log(Debug::Warning) << error;
|
|
|
|
if (!isPlayer)
|
|
|
|
return;
|
2023-05-12 13:24:59 +02:00
|
|
|
const ESM::ExteriorCellLocation cellIndex
|
2023-05-27 01:18:17 +02:00
|
|
|
= ESM::positionToExteriorCellLocation(x, y, store->getCell()->getWorldSpace());
|
2023-05-12 12:04:04 +02:00
|
|
|
store = &worldModel->getExterior(cellIndex);
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
|
|
|
if (store)
|
|
|
|
{
|
2015-09-30 10:30:50 +02:00
|
|
|
MWWorld::Ptr base = ptr;
|
2022-10-31 12:29:29 +01:00
|
|
|
ptr = world->moveObject(ptr, store, osg::Vec3f(x, y, z));
|
2022-09-22 21:26:05 +03:00
|
|
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(base, ptr);
|
2014-08-11 02:01:20 +02:00
|
|
|
|
2021-04-11 19:17:17 +02:00
|
|
|
auto rot = ptr.getRefData().getPosition().asRotationVec3();
|
2022-09-22 21:26:05 +03:00
|
|
|
// Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south
|
|
|
|
// = 10800, west = 16200) except for when you position the player, then degrees must be used. See
|
|
|
|
// "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference.
|
|
|
|
if (!isPlayer)
|
|
|
|
zRot = zRot / 60.0f;
|
2021-04-11 19:17:17 +02:00
|
|
|
rot.z() = osg::DegreesToRadians(zRot);
|
2022-10-31 12:29:29 +01:00
|
|
|
world->rotateObject(ptr, rot);
|
2022-09-22 21:26:05 +03:00
|
|
|
|
2022-11-06 20:06:45 +01:00
|
|
|
bool cellActive = MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell());
|
|
|
|
ptr.getClass().adjustPosition(ptr, isPlayer || !cellActive);
|
2012-08-05 16:44:56 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2012-08-05 16:44:56 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
|
|
|
class OpPosition : public Interpreter::Opcode0
|
2012-09-02 17:57:03 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2012-09-02 17:57:03 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
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();
|
|
|
|
|
|
|
|
if (!ptr.isInCell())
|
|
|
|
return;
|
|
|
|
|
2022-10-31 12:29:29 +01:00
|
|
|
bool isPlayer = ptr == MWMechanics::getPlayer();
|
|
|
|
auto world = MWBase::Environment::get().getWorld();
|
2023-05-13 15:26:39 +02:00
|
|
|
if (ptr.getClass().isActor())
|
|
|
|
ptr.getClass().getCreatureStats(ptr).setTeleported(true);
|
2022-10-31 12:29:29 +01:00
|
|
|
if (isPlayer)
|
|
|
|
world->getPlayer().setTeleported(true);
|
2023-05-12 13:24:59 +02:00
|
|
|
const ESM::ExteriorCellLocation cellIndex
|
2023-05-27 01:18:17 +02:00
|
|
|
= ESM::positionToExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId);
|
2022-09-22 21:26:05 +03:00
|
|
|
|
|
|
|
// another morrowind oddity: player will be moved to the exterior cell at this location,
|
|
|
|
// non-player actors will move within the cell they are in.
|
|
|
|
MWWorld::Ptr base = ptr;
|
2022-10-31 12:29:29 +01:00
|
|
|
if (isPlayer)
|
2022-09-22 21:26:05 +03:00
|
|
|
{
|
2023-05-12 12:04:04 +02:00
|
|
|
MWWorld::CellStore* cell = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex);
|
2022-10-31 12:29:29 +01:00
|
|
|
ptr = world->moveObject(ptr, cell, osg::Vec3(x, y, z));
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-10-31 12:29:29 +01:00
|
|
|
ptr = world->moveObject(ptr, osg::Vec3f(x, y, z), true, true);
|
2012-09-02 17:57:03 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(base, ptr);
|
|
|
|
|
|
|
|
auto rot = ptr.getRefData().getPosition().asRotationVec3();
|
|
|
|
// Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south =
|
|
|
|
// 10800, west = 16200) except for when you position the player, then degrees must be used. See
|
|
|
|
// "Morrowind Scripting for Dummies (9th Edition)" pages 50 and 54 for reference.
|
2022-10-31 12:29:29 +01:00
|
|
|
if (!isPlayer)
|
2022-09-22 21:26:05 +03:00
|
|
|
zRot = zRot / 60.0f;
|
|
|
|
rot.z() = osg::DegreesToRadians(zRot);
|
2022-10-31 12:29:29 +01:00
|
|
|
world->rotateObject(ptr, rot);
|
2022-11-06 20:06:45 +01:00
|
|
|
bool cellActive = MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell());
|
|
|
|
ptr.getClass().adjustPosition(ptr, isPlayer || !cellActive);
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2012-09-02 17:57:03 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
class OpPlaceItemCell : public Interpreter::Opcode0
|
2012-09-02 17:57:03 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
const ESM::RefId itemID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.pop();
|
2023-01-19 17:31:45 +01:00
|
|
|
std::string_view cellName = runtime.getStringLiteral(runtime[0].mInteger);
|
2022-09-22 21:26:05 +03:00
|
|
|
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 zRotDegrees = runtime[0].mFloat;
|
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
MWWorld::CellStore* store = nullptr;
|
|
|
|
try
|
2012-09-02 17:57:03 +02:00
|
|
|
{
|
2023-04-20 15:55:40 +02:00
|
|
|
store = &MWBase::Environment::get().getWorldModel()->getCell(cellName);
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
2023-01-19 17:31:45 +01:00
|
|
|
runtime.getContext().report("unknown cell (" + std::string(cellName) + ")");
|
|
|
|
Log(Debug::Error) << "Error: unknown cell (" << cellName << ")";
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
|
|
|
if (store)
|
|
|
|
{
|
2014-09-08 23:57:16 +02:00
|
|
|
ESM::Position pos;
|
|
|
|
pos.pos[0] = x;
|
|
|
|
pos.pos[1] = y;
|
|
|
|
pos.pos[2] = z;
|
|
|
|
pos.rot[0] = pos.rot[1] = 0;
|
2015-11-11 21:19:50 +01:00
|
|
|
pos.rot[2] = osg::DegreesToRadians(zRotDegrees);
|
2023-04-20 21:07:53 +02:00
|
|
|
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), itemID);
|
2021-03-05 22:21:53 +01:00
|
|
|
ref.getPtr().mRef->mData.mPhysicsPostponed = !ref.getPtr().getClass().isActor();
|
2014-09-08 23:57:16 +02:00
|
|
|
ref.getPtr().getCellRef().setPosition(pos);
|
2022-09-22 21:26:05 +03:00
|
|
|
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), store, pos);
|
2014-12-11 22:25:53 +01:00
|
|
|
placed.getClass().adjustPosition(placed, true);
|
2012-09-02 17:57:03 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2012-09-02 17:57:03 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
class OpPlaceItem : public Interpreter::Opcode0
|
2012-09-02 17:57:03 +02:00
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
ESM::RefId itemID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
|
2022-09-22 21:26:05 +03:00
|
|
|
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 zRotDegrees = runtime[0].mFloat;
|
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
|
|
|
|
|
|
|
if (!player.isInCell())
|
|
|
|
throw std::runtime_error("player not in a cell");
|
2012-09-02 17:57:03 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
MWWorld::CellStore* store = nullptr;
|
|
|
|
if (player.getCell()->isExterior())
|
2012-09-02 17:57:03 +02:00
|
|
|
{
|
2023-05-12 13:24:59 +02:00
|
|
|
const ESM::ExteriorCellLocation cellIndex
|
2023-05-27 01:18:17 +02:00
|
|
|
= ESM::positionToExteriorCellLocation(x, y, player.getCell()->getCell()->getWorldSpace());
|
2023-05-12 12:04:04 +02:00
|
|
|
store = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex);
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
store = player.getCell();
|
|
|
|
|
|
|
|
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] = osg::DegreesToRadians(zRotDegrees);
|
2023-04-20 21:07:53 +02:00
|
|
|
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), itemID);
|
2022-09-22 21:26:05 +03:00
|
|
|
ref.getPtr().mRef->mData.mPhysicsPostponed = !ref.getPtr().getClass().isActor();
|
|
|
|
ref.getPtr().getCellRef().setPosition(pos);
|
|
|
|
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), store, pos);
|
|
|
|
placed.getClass().adjustPosition(placed, true);
|
|
|
|
}
|
|
|
|
};
|
2012-09-02 17:57:03 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R, bool pc>
|
|
|
|
class OpPlaceAt : public Interpreter::Opcode0
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr actor = pc ? MWMechanics::getPlayer() : R()(runtime);
|
2012-09-02 17:57:03 +02:00
|
|
|
|
Initial commit: In ESM structures, replace the string members that are RefIds to other records, to a new strong type
The strong type is actually just a string underneath, but this will help in the future to have a distinction so it's easier to search and replace when we use an integer ID
Slowly going through all the changes to make, still hundreds of errors
a lot of functions/structures use std::string or stringview to designate an ID. So it takes time
Continues slowly replacing ids. There are technically more and more compilation errors
I have good hope that there is a point where the amount of errors will dramatically go down as all the main functions use the ESM::RefId type
Continue moving forward, changes to the stores
slowly moving along
Starting to see the fruit of those changes.
still many many error, but more and more Irun into a situation where a function is sandwiched between two functions that use the RefId type.
More replacements. Things are starting to get easier
I can see more and more often the issue is that the function is awaiting a RefId, but is given a string
there is less need to go down functions and to fix a long list of them.
Still moving forward, and for the first time error count is going down!
Good pace, not sure about topics though, mId and mName are actually the same thing and are used interchangeably
Cells are back to using string for the name, haven't fixed everything yet. Many other changes
Under the bar of 400 compilation errors.
more good progress <100 compile errors!
More progress
Game settings store can use string for find, it was a bit absurd how every use of it required to create refId from string
some more progress on other fronts
Mostly game settings clean
one error opened a lot of other errors. Down to 18, but more will prbably appear
only link errors left??
Fixed link errors
OpenMW compiles, and launches, with some issues, but still!
2022-09-25 13:17:09 +02:00
|
|
|
ESM::RefId itemID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
|
2022-09-22 21:26:05 +03:00
|
|
|
runtime.pop();
|
2012-09-02 17:57:03 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
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();
|
2016-06-02 21:19:02 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (direction < 0 || direction > 3)
|
|
|
|
throw std::runtime_error("invalid direction");
|
2013-04-06 19:25:29 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (count < 0)
|
|
|
|
throw std::runtime_error("count must be non-negative");
|
2015-12-09 00:48:51 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (!actor.isInCell())
|
|
|
|
throw std::runtime_error("actor is not in a cell");
|
2012-09-17 13:36:48 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
// create item
|
2023-04-20 21:07:53 +02:00
|
|
|
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), itemID, 1);
|
2022-09-22 21:26:05 +03:00
|
|
|
ref.getPtr().mRef->mData.mPhysicsPostponed = !ref.getPtr().getClass().isActor();
|
|
|
|
|
|
|
|
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->safePlaceObject(
|
|
|
|
ref.getPtr(), actor, actor.getCell(), direction, distance);
|
|
|
|
MWBase::Environment::get().getWorld()->scaleObject(ptr, actor.getCellRef().getScale());
|
2012-09-02 17:57:03 +02:00
|
|
|
}
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2012-09-02 17:57:03 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2013-04-10 22:53:03 +02:00
|
|
|
class OpRotate : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
const MWWorld::Ptr& ptr = R()(runtime);
|
|
|
|
|
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
|
|
|
Interpreter::Type_Float rotation
|
|
|
|
= osg::DegreesToRadians(runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
|
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
auto rot = ptr.getRefData().getPosition().asRotationVec3();
|
|
|
|
// Regardless of the axis argument, the player may only be rotated on Z
|
|
|
|
if (axis == "z" || MWMechanics::getPlayer() == ptr)
|
|
|
|
rot.z() += rotation;
|
|
|
|
else if (axis == "x")
|
|
|
|
rot.x() += rotation;
|
|
|
|
else if (axis == "y")
|
|
|
|
rot.y() += rotation;
|
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(ptr, rot);
|
|
|
|
}
|
2013-04-10 22:53:03 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2013-04-15 16:45:53 +02:00
|
|
|
class OpRotateWorld : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
|
|
|
|
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
|
|
|
Interpreter::Type_Float rotation
|
|
|
|
= osg::DegreesToRadians(runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
|
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
if (!ptr.getRefData().getBaseNode())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We can rotate actors only around Z axis
|
|
|
|
if (ptr.getClass().isActor() && (axis == "x" || axis == "y"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
osg::Quat rot;
|
|
|
|
if (axis == "x")
|
|
|
|
rot = osg::Quat(rotation, -osg::X_AXIS);
|
|
|
|
else if (axis == "y")
|
|
|
|
rot = osg::Quat(rotation, -osg::Y_AXIS);
|
|
|
|
else if (axis == "z")
|
|
|
|
rot = osg::Quat(rotation, -osg::Z_AXIS);
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
osg::Quat attitude = ptr.getRefData().getBaseNode()->getAttitude();
|
|
|
|
MWBase::Environment::get().getWorld()->rotateWorldObject(ptr, attitude * rot);
|
|
|
|
}
|
2013-04-15 16:45:53 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2013-04-26 02:02:51 +02:00
|
|
|
class OpSetAtStart : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
2014-01-02 03:06:48 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (!ptr.isInCell())
|
|
|
|
return;
|
2014-12-11 19:27:13 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
MWBase::Environment::get().getWorld()->rotateObject(
|
|
|
|
ptr, ptr.getCellRef().getPosition().asRotationVec3());
|
2013-04-26 02:02:51 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
|
|
|
|
.updatePtr(ptr,
|
|
|
|
MWBase::Environment::get().getWorld()->moveObject(
|
|
|
|
ptr, ptr.getCellRef().getPosition().asVec3()));
|
|
|
|
}
|
2013-04-26 02:02:51 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2013-04-26 17:28:19 +02:00
|
|
|
class OpMove : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
const MWWorld::Ptr& ptr = R()(runtime);
|
2013-04-26 17:28:19 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
if (!ptr.isInCell())
|
|
|
|
return;
|
2014-01-02 03:06:48 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
|
|
|
Interpreter::Type_Float movement = (runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
|
|
|
|
runtime.pop();
|
2013-04-26 17:28:19 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
osg::Vec3f posChange;
|
|
|
|
if (axis == "x")
|
|
|
|
{
|
|
|
|
posChange = osg::Vec3f(movement, 0, 0);
|
|
|
|
}
|
|
|
|
else if (axis == "y")
|
|
|
|
{
|
|
|
|
posChange = osg::Vec3f(0, movement, 0);
|
|
|
|
}
|
|
|
|
else if (axis == "z")
|
|
|
|
{
|
|
|
|
posChange = osg::Vec3f(0, 0, movement);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
2013-04-26 17:28:19 +02:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
// is it correct that disabled objects can't be Move-d?
|
|
|
|
if (!ptr.getRefData().getBaseNode())
|
|
|
|
return;
|
2014-12-27 17:20:37 +01:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
osg::Vec3f diff = ptr.getRefData().getBaseNode()->getAttitude() * posChange;
|
2018-08-25 10:34:33 +04:00
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
// We should move actors, standing on moving object, too.
|
|
|
|
// This approach can be used to create elevators.
|
|
|
|
moveStandingActors(ptr, diff);
|
|
|
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
|
In 0.46, SetPos was setting position of actors before physics simulation, and from this position movement was simulated. This changed with async physics merging, and at the same time problems started, mostly with abot's scenic travel.
Skipping the simulation, switching off collisions, and other approaches were not correct as they either broke some mods, or some core mechanics of the engine such as teleportation or waterwalking. As it turns out, the way to go is to simply do _nothing_ (modulo some gymnastics to account for the 1 frame difference in case of async).
Scripted movement and the unstucking logic tends to collide. Early out of unstuck in case the actor doesn't attempt to move. This means there is no AI package for NPC, which are the case for some boats and striders, or the player is content with their position.
2023-03-16 21:33:36 +01:00
|
|
|
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2013-04-26 17:28:19 +02:00
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
template <class R>
|
2013-04-26 17:28:19 +02:00
|
|
|
class OpMoveWorld : public Interpreter::Opcode0
|
|
|
|
{
|
2022-09-22 21:26:05 +03:00
|
|
|
public:
|
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
|
|
|
{
|
|
|
|
MWWorld::Ptr ptr = R()(runtime);
|
|
|
|
|
|
|
|
if (!ptr.isInCell())
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
|
|
|
|
runtime.pop();
|
|
|
|
Interpreter::Type_Float movement = (runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
|
|
|
|
runtime.pop();
|
|
|
|
|
|
|
|
osg::Vec3f diff;
|
|
|
|
|
|
|
|
if (axis == "x")
|
|
|
|
diff.x() = movement;
|
|
|
|
else if (axis == "y")
|
|
|
|
diff.y() = movement;
|
|
|
|
else if (axis == "z")
|
|
|
|
diff.z() = movement;
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We should move actors, standing on moving object, too.
|
|
|
|
// This approach can be used to create elevators.
|
|
|
|
moveStandingActors(ptr, diff);
|
|
|
|
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
|
In 0.46, SetPos was setting position of actors before physics simulation, and from this position movement was simulated. This changed with async physics merging, and at the same time problems started, mostly with abot's scenic travel.
Skipping the simulation, switching off collisions, and other approaches were not correct as they either broke some mods, or some core mechanics of the engine such as teleportation or waterwalking. As it turns out, the way to go is to simply do _nothing_ (modulo some gymnastics to account for the 1 frame difference in case of async).
Scripted movement and the unstucking logic tends to collide. Early out of unstuck in case the actor doesn't attempt to move. This means there is no AI package for NPC, which are the case for some boats and striders, or the player is content with their position.
2023-03-16 21:33:36 +01:00
|
|
|
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
|
2022-09-22 21:26:05 +03:00
|
|
|
}
|
2013-04-26 17:28:19 +02:00
|
|
|
};
|
|
|
|
|
2014-08-30 17:55:35 +02:00
|
|
|
class OpResetActors : public Interpreter::Opcode0
|
|
|
|
{
|
|
|
|
public:
|
2022-09-22 21:26:05 +03:00
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
2014-08-30 17:55:35 +02:00
|
|
|
{
|
|
|
|
MWBase::Environment::get().getWorld()->resetActors();
|
|
|
|
}
|
|
|
|
};
|
2013-04-26 17:28:19 +02:00
|
|
|
|
2016-01-20 04:07:07 +01:00
|
|
|
class OpFixme : public Interpreter::Opcode0
|
|
|
|
{
|
|
|
|
public:
|
2022-09-22 21:26:05 +03:00
|
|
|
void execute(Interpreter::Runtime& runtime) override
|
2016-01-20 04:07:07 +01:00
|
|
|
{
|
2018-10-24 01:40:57 +03:00
|
|
|
MWBase::Environment::get().getWorld()->fixPosition();
|
2016-01-20 04:07:07 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-09-22 21:26:05 +03:00
|
|
|
void installOpcodes(Interpreter::Interpreter& interpreter)
|
2012-07-09 18:47:59 +02:00
|
|
|
{
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpGetDistance<ImplicitRef>>(Compiler::Transformation::opcodeGetDistance);
|
2022-09-22 21:26:05 +03:00
|
|
|
interpreter.installSegment5<OpGetDistance<ExplicitRef>>(
|
|
|
|
Compiler::Transformation::opcodeGetDistanceExplicit);
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpSetScale<ImplicitRef>>(Compiler::Transformation::opcodeSetScale);
|
|
|
|
interpreter.installSegment5<OpSetScale<ExplicitRef>>(Compiler::Transformation::opcodeSetScaleExplicit);
|
|
|
|
interpreter.installSegment5<OpSetAngle<ImplicitRef>>(Compiler::Transformation::opcodeSetAngle);
|
|
|
|
interpreter.installSegment5<OpSetAngle<ExplicitRef>>(Compiler::Transformation::opcodeSetAngleExplicit);
|
|
|
|
interpreter.installSegment5<OpGetScale<ImplicitRef>>(Compiler::Transformation::opcodeGetScale);
|
|
|
|
interpreter.installSegment5<OpGetScale<ExplicitRef>>(Compiler::Transformation::opcodeGetScaleExplicit);
|
|
|
|
interpreter.installSegment5<OpGetAngle<ImplicitRef>>(Compiler::Transformation::opcodeGetAngle);
|
|
|
|
interpreter.installSegment5<OpGetAngle<ExplicitRef>>(Compiler::Transformation::opcodeGetAngleExplicit);
|
|
|
|
interpreter.installSegment5<OpGetPos<ImplicitRef>>(Compiler::Transformation::opcodeGetPos);
|
|
|
|
interpreter.installSegment5<OpGetPos<ExplicitRef>>(Compiler::Transformation::opcodeGetPosExplicit);
|
|
|
|
interpreter.installSegment5<OpSetPos<ImplicitRef>>(Compiler::Transformation::opcodeSetPos);
|
|
|
|
interpreter.installSegment5<OpSetPos<ExplicitRef>>(Compiler::Transformation::opcodeSetPosExplicit);
|
|
|
|
interpreter.installSegment5<OpGetStartingPos<ImplicitRef>>(Compiler::Transformation::opcodeGetStartingPos);
|
2022-09-22 21:26:05 +03:00
|
|
|
interpreter.installSegment5<OpGetStartingPos<ExplicitRef>>(
|
|
|
|
Compiler::Transformation::opcodeGetStartingPosExplicit);
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpPosition<ImplicitRef>>(Compiler::Transformation::opcodePosition);
|
|
|
|
interpreter.installSegment5<OpPosition<ExplicitRef>>(Compiler::Transformation::opcodePositionExplicit);
|
|
|
|
interpreter.installSegment5<OpPositionCell<ImplicitRef>>(Compiler::Transformation::opcodePositionCell);
|
2022-09-22 21:26:05 +03:00
|
|
|
interpreter.installSegment5<OpPositionCell<ExplicitRef>>(
|
|
|
|
Compiler::Transformation::opcodePositionCellExplicit);
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpPlaceItemCell>(Compiler::Transformation::opcodePlaceItemCell);
|
|
|
|
interpreter.installSegment5<OpPlaceItem>(Compiler::Transformation::opcodePlaceItem);
|
|
|
|
interpreter.installSegment5<OpPlaceAt<ImplicitRef, true>>(Compiler::Transformation::opcodePlaceAtPc);
|
|
|
|
interpreter.installSegment5<OpPlaceAt<ImplicitRef, false>>(Compiler::Transformation::opcodePlaceAtMe);
|
2022-09-22 21:26:05 +03:00
|
|
|
interpreter.installSegment5<OpPlaceAt<ExplicitRef, false>>(
|
|
|
|
Compiler::Transformation::opcodePlaceAtMeExplicit);
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpModScale<ImplicitRef>>(Compiler::Transformation::opcodeModScale);
|
|
|
|
interpreter.installSegment5<OpModScale<ExplicitRef>>(Compiler::Transformation::opcodeModScaleExplicit);
|
|
|
|
interpreter.installSegment5<OpRotate<ImplicitRef>>(Compiler::Transformation::opcodeRotate);
|
|
|
|
interpreter.installSegment5<OpRotate<ExplicitRef>>(Compiler::Transformation::opcodeRotateExplicit);
|
|
|
|
interpreter.installSegment5<OpRotateWorld<ImplicitRef>>(Compiler::Transformation::opcodeRotateWorld);
|
2022-09-22 21:26:05 +03:00
|
|
|
interpreter.installSegment5<OpRotateWorld<ExplicitRef>>(
|
|
|
|
Compiler::Transformation::opcodeRotateWorldExplicit);
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpSetAtStart<ImplicitRef>>(Compiler::Transformation::opcodeSetAtStart);
|
|
|
|
interpreter.installSegment5<OpSetAtStart<ExplicitRef>>(Compiler::Transformation::opcodeSetAtStartExplicit);
|
|
|
|
interpreter.installSegment5<OpMove<ImplicitRef>>(Compiler::Transformation::opcodeMove);
|
|
|
|
interpreter.installSegment5<OpMove<ExplicitRef>>(Compiler::Transformation::opcodeMoveExplicit);
|
|
|
|
interpreter.installSegment5<OpMoveWorld<ImplicitRef>>(Compiler::Transformation::opcodeMoveWorld);
|
|
|
|
interpreter.installSegment5<OpMoveWorld<ExplicitRef>>(Compiler::Transformation::opcodeMoveWorldExplicit);
|
2022-09-22 21:26:05 +03:00
|
|
|
interpreter.installSegment5<OpGetStartingAngle<ImplicitRef>>(
|
|
|
|
Compiler::Transformation::opcodeGetStartingAngle);
|
|
|
|
interpreter.installSegment5<OpGetStartingAngle<ExplicitRef>>(
|
|
|
|
Compiler::Transformation::opcodeGetStartingAngleExplicit);
|
2022-01-27 19:18:57 +00:00
|
|
|
interpreter.installSegment5<OpResetActors>(Compiler::Transformation::opcodeResetActors);
|
|
|
|
interpreter.installSegment5<OpFixme>(Compiler::Transformation::opcodeFixme);
|
2012-07-09 18:47:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|