1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 12:39:55 +00:00
OpenMW/apps/openmw/mwscript/transformationextensions.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

868 lines
36 KiB
C++
Raw Normal View History

2018-08-14 23:05:43 +04:00
#include <components/debug/debuglog.hpp>
2015-06-03 23:04:35 +02:00
#include <components/sceneutil/positionattitudetransform.hpp>
2012-09-18 10:49:51 +02:00
#include <components/esm3/loadcell.hpp>
2012-07-09 18:47:59 +02:00
#include <components/compiler/opcodes.hpp>
2012-07-09 18:47:59 +02:00
#include <components/interpreter/interpreter.hpp>
#include <components/interpreter/opcodes.hpp>
#include <components/interpreter/runtime.hpp>
#include "../mwbase/environment.hpp"
#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"
#include "../mwworld/player.hpp"
#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"
#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
{
void moveStandingActors(const MWWorld::Ptr& ptr, const osg::Vec3f& diff)
{
std::vector<MWWorld::Ptr> actors;
MWBase::Environment::get().getWorld()->getActorsStandingOn(ptr, actors);
for (auto& actor : actors)
MWBase::Environment::get().getWorld()->moveObjectBy(actor, diff, false);
}
template <class R>
class OpGetDistance : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03:00
{
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));
runtime.pop();
if (from.isEmpty())
{
std::string error = "Missing implicit ref";
runtime.getContext().report(error);
Log(Debug::Error) << error;
runtime.push(0.f);
return;
}
if (from.getContainerStore()) // is the object contained?
{
MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(from);
if (!container.isEmpty())
from = container;
2022-09-22 21:26:05 +03:00
else
{
const std::string error
= "Failed to find the container of object " + from.getCellRef().getRefId().toDebugString();
runtime.getContext().report(error);
Log(Debug::Error) << error;
runtime.push(0.f);
return;
}
2022-09-22 21:26:05 +03:00
}
const MWWorld::Ptr to = MWBase::Environment::get().getWorld()->searchPtr(name, false);
if (to.isEmpty())
2022-09-22 21:26:05 +03:00
{
const std::string error = "Failed to find an instance of object " + name.toDebugString();
runtime.getContext().report(error);
Log(Debug::Error) << error;
runtime.push(0.f);
2022-09-22 21:26:05 +03:00
return;
}
float distance;
// If the objects are in different worldspaces, return a large value (just like vanilla)
if (!to.isInCell() || !from.isInCell()
|| to.getCell()->getCell()->getWorldSpace() != from.getCell()->getCell()->getWorldSpace())
distance = std::numeric_limits<float>::max();
2022-09-22 21:26:05 +03:00
else
{
double diff[3];
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];
distance = static_cast<float>(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2]));
}
2022-09-22 21:26:05 +03:00
runtime.push(distance);
2022-09-22 21:26:05 +03:00
}
};
2012-07-09 18:47:59 +02:00
template <class R>
class OpSetScale : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2012-07-09 18:47:59 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float scale = runtime[0].mFloat;
2012-07-09 18:47:59 +02:00
runtime.pop();
MWBase::Environment::get().getWorld()->scaleObject(ptr, scale);
}
};
template <class R>
class OpGetScale : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
runtime.push(ptr.getCellRef().getScale());
}
};
template <class R>
class OpModScale : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
Interpreter::Type_Float scale = runtime[0].mFloat;
runtime.pop();
// add the parameter to the object's scale.
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale() + scale);
}
};
2012-07-09 18:47:59 +02:00
template <class R>
class OpSetAngle : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2012-07-09 18:47:59 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
2022-09-22 21:26:05 +03:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
2012-07-09 18:47:59 +02:00
runtime.pop();
Interpreter::Type_Float angle = osg::DegreesToRadians(runtime[0].mFloat);
2012-07-09 18:47:59 +02:00
runtime.pop();
2022-09-22 21:26:05 +03:00
float ax = ptr.getRefData().getPosition().rot[0];
float ay = ptr.getRefData().getPosition().rot[1];
float az = ptr.getRefData().getPosition().rot[2];
2022-09-22 21:26:05 +03:00
// 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
}
};
template <class R>
2012-08-01 12:21:42 +02:00
class OpGetStartingAngle : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
runtime.pop();
2022-04-30 16:45:45 +02:00
float ret = 0.f;
if (!axis.empty())
2022-09-22 21:26:05 +03:00
{
2022-04-30 16:45:45 +02:00
if (axis[0] == 'x')
2022-09-22 21:26:05 +03:00
{
2022-04-30 16:45:45 +02:00
ret = osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[0]);
2022-09-22 21:26:05 +03:00
}
2022-04-30 16:45:45 +02:00
else if (axis[0] == 'y')
{
2022-04-30 16:45:45 +02:00
ret = osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[1]);
}
else if (axis[0] == 'z')
{
ret = osg::RadiansToDegrees(ptr.getCellRef().getPosition().rot[2]);
}
}
2022-04-30 16:45:45 +02:00
runtime.push(ret);
2022-09-22 21:26:05 +03:00
}
};
2012-08-01 12:21:42 +02:00
template <class R>
class OpGetAngle : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2012-08-01 12:21:42 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
2012-08-01 12:21:42 +02:00
runtime.pop();
2022-04-30 16:45:45 +02:00
float ret = 0.f;
if (!axis.empty())
2022-09-22 21:26:05 +03:00
{
2022-04-30 16:45:45 +02:00
if (axis[0] == 'x')
2012-08-01 12:21:42 +02:00
{
2022-04-30 16:45:45 +02:00
ret = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[0]);
2012-08-01 12:21:42 +02:00
}
2022-04-30 16:45:45 +02:00
else if (axis[0] == 'y')
{
2022-05-05 21:53:20 +02:00
ret = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[1]);
2022-04-30 16:45:45 +02:00
}
else if (axis[0] == 'z')
{
2022-05-05 21:53:20 +02:00
ret = osg::RadiansToDegrees(ptr.getRefData().getPosition().rot[2]);
}
}
2022-04-30 16:45:45 +02:00
runtime.push(ret);
2022-09-22 21:26:05 +03:00
}
};
template <class R>
class OpGetPos : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
MWWorld::Ptr ptr = R()(runtime);
2022-04-30 16:45:45 +02:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
runtime.pop();
2021-03-13 09:53:21 +01:00
float ret = 0.f;
2012-08-05 16:21:53 +02:00
if (!axis.empty())
{
if (axis[0] == 'x')
{
2021-03-13 09:53:21 +01:00
ret = ptr.getRefData().getPosition().pos[0];
}
else if (axis[0] == 'y')
{
ret = ptr.getRefData().getPosition().pos[1];
}
2012-09-18 10:49:51 +02:00
else if (axis[0] == 'z')
{
ret = ptr.getRefData().getPosition().pos[2];
}
}
2022-04-30 16:45:45 +02:00
runtime.push(ret);
2022-09-22 21:26:05 +03:00
}
};
2012-08-03 18:20:51 +02:00
template <class R>
class OpSetPos : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03:00
{
MWWorld::Ptr ptr = R()(runtime);
2012-08-03 18:20:51 +02:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
runtime.pop();
Interpreter::Type_Float pos = runtime[0].mFloat;
2012-08-03 18:20:51 +02:00
runtime.pop();
if (!ptr.isInCell())
return;
2012-08-03 18:20:51 +02:00
2022-04-30 16:45:45 +02:00
// Note: SetPos does not skip weather transitions in vanilla engine, so we do not call
// setTeleported(true) here.
2022-09-22 21:26:05 +03:00
2022-04-30 16:45:45 +02:00
const auto curPos = ptr.getRefData().getPosition().asVec3();
2021-03-13 09:53:21 +01:00
auto newPos = curPos;
if (axis == "x")
2022-09-22 21:26:05 +03:00
{
2021-03-13 09:53:21 +01:00
newPos[0] = pos;
2022-09-22 21:26:05 +03:00
}
2022-04-30 16:45:45 +02:00
else if (axis == "y")
2022-09-22 21:26:05 +03:00
{
2021-03-13 09:53:21 +01:00
newPos[1] = pos;
2022-09-22 21:26:05 +03:00
}
2013-04-15 16:45:53 +02:00
else if (axis == "z")
2022-09-22 21:26:05 +03:00
{
// We should not place actors under ground
2022-04-30 16:45:45 +02:00
if (ptr.getClass().isActor())
2012-08-03 18:20:51 +02:00
{
2022-05-05 21:53:20 +02:00
float terrainHeight = -std::numeric_limits<float>::max();
if (ptr.getCell()->isExterior())
terrainHeight = MWBase::Environment::get().getWorld()->getTerrainHeightAt(
curPos, ptr.getCell()->getCell()->getWorldSpace());
2022-09-22 21:26:05 +03:00
2022-04-30 16:45:45 +02:00
if (pos < terrainHeight)
2022-05-05 21:53:20 +02:00
pos = terrainHeight;
2012-08-03 18:20:51 +02:00
}
2022-09-22 21:26:05 +03:00
2021-03-13 09:53:21 +01:00
newPos[2] = pos;
2022-09-22 21:26:05 +03:00
}
else
{
2022-04-30 16:45:45 +02:00
return;
2012-08-03 18:20:51 +02:00
}
2022-09-22 21:26:05 +03:00
2021-03-13 09:53:21 +01:00
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext())
.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
};
2012-08-09 23:45:06 +02:00
template <class R>
class OpGetStartingPos : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2012-08-09 23:45:06 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
2022-04-30 16:45:45 +02:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
runtime.pop();
2020-11-13 11:39:47 +04:00
float ret = 0.f;
if (!axis.empty())
2022-09-22 21:26:05 +03:00
{
2022-04-30 16:45:45 +02:00
if (axis[0] == 'x')
{
2012-08-18 10:50:58 +02:00
ret = ptr.getCellRef().getPosition().pos[0];
}
else if (axis[0] == 'y')
2012-08-11 09:52:49 +02:00
{
ret = ptr.getCellRef().getPosition().pos[1];
2012-08-11 09:52:49 +02:00
}
else if (axis[0] == 'z')
2012-08-09 23:45:06 +02:00
{
ret = ptr.getCellRef().getPosition().pos[2];
2012-08-18 10:50:58 +02:00
}
2012-08-09 23:45:06 +02:00
}
2022-04-30 16:45:45 +02:00
runtime.push(ret);
2022-09-22 21:26:05 +03:00
}
2012-08-09 23:45:06 +02:00
};
template <class R>
class OpPositionCell : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03:00
{
2012-08-09 23:45:06 +02:00
MWWorld::Ptr ptr = R()(runtime);
2022-09-22 21:26:05 +03:00
2012-08-09 23:45:06 +02: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();
2023-01-19 17:31:45 +01:00
std::string_view cellID = runtime.getStringLiteral(runtime[0].mInteger);
2012-08-09 23:45:06 +02:00
runtime.pop();
2022-09-22 21:26:05 +03:00
if (ptr.getContainerStore())
2022-09-22 21:26:05 +03:00
return;
2022-04-30 16:45:45 +02:00
bool isPlayer = ptr == MWMechanics::getPlayer();
auto world = MWBase::Environment::get().getWorld();
auto worldModel = MWBase::Environment::get().getWorldModel();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).setTeleported(true);
2022-04-30 16:45:45 +02:00
if (isPlayer)
world->getPlayer().setTeleported(true);
2022-04-30 16:45:45 +02:00
MWWorld::CellStore* store = nullptr;
2022-09-22 21:26:05 +03:00
try
{
store = &worldModel->getCell(cellID);
if (store->isExterior())
{
const ESM::ExteriorCellLocation cellIndex
= ESM::positionToExteriorCellLocation(x, y, store->getCell()->getWorldSpace());
store = &worldModel->getExterior(cellIndex);
}
2022-09-22 21:26:05 +03:00
}
2022-04-30 16:45:45 +02:00
catch (std::exception&)
2022-09-22 21:26:05 +03:00
{
2022-04-30 16:45:45 +02:00
// cell not found, move to exterior instead if moving the player (vanilla PositionCell
2021-12-26 15:27:25 +00:00
// compatibility)
2023-01-19 17:31:45 +01:00
std::string error = "Warning: PositionCell: unknown interior cell (" + std::string(cellID) + ")";
if (isPlayer)
error += ", moving to exterior instead";
runtime.getContext().report(error);
Log(Debug::Warning) << error;
if (!isPlayer)
return;
store = &worldModel->getExterior(
ESM::positionToExteriorCellLocation(x, y, ESM::Cell::sDefaultWorldspaceId));
2022-09-22 21:26:05 +03:00
}
if (store)
2022-09-22 21:26:05 +03:00
{
MWWorld::Ptr base = ptr;
ptr = world->moveObject(ptr, store, osg::Vec3f(x, y, z));
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.
2015-08-21 21:12:39 +12:00
if (!isPlayer)
zRot = zRot / 60.0f;
rot.z() = osg::DegreesToRadians(zRot);
world->rotateObject(ptr, rot);
2022-09-22 21:26:05 +03:00
bool cellActive = MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell());
ptr.getClass().adjustPosition(ptr, isPlayer || !cellActive);
}
2022-09-22 21:26:05 +03:00
}
};
template <class R>
class OpPosition : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03:00
{
2012-08-09 23:45:06 +02:00
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();
2022-09-22 21:26:05 +03:00
2022-04-30 16:45:45 +02:00
if (!ptr.isInCell())
2022-09-22 21:26:05 +03:00
return;
bool isPlayer = ptr == MWMechanics::getPlayer();
auto world = MWBase::Environment::get().getWorld();
if (ptr.getClass().isActor())
ptr.getClass().getCreatureStats(ptr).setTeleported(true);
if (isPlayer)
world->getPlayer().setTeleported(true);
const ESM::ExteriorCellLocation cellIndex
= 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;
if (isPlayer)
2022-09-22 21:26:05 +03:00
{
MWWorld::CellStore* cell = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex);
ptr = world->moveObject(ptr, cell, osg::Vec3(x, y, z));
2022-09-22 21:26:05 +03:00
}
else
2022-09-22 21:26:05 +03:00
{
ptr = world->moveObject(ptr, osg::Vec3f(x, y, z), true, true);
}
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(base, ptr);
2022-09-22 21:26:05 +03:00
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.
if (!isPlayer)
zRot = zRot / 60.0f;
rot.z() = osg::DegreesToRadians(zRot);
world->rotateObject(ptr, rot);
bool cellActive = MWBase::Environment::get().getWorldScene()->isCellActive(*ptr.getCell());
ptr.getClass().adjustPosition(ptr, isPlayer || !cellActive);
2022-09-22 21:26:05 +03:00
}
};
class OpPlaceItemCell : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03: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
const ESM::RefId itemID = ESM::RefId::stringRefId(runtime.getStringLiteral(runtime[0].mInteger));
runtime.pop();
2023-01-19 17:31:45 +01:00
std::string_view cellName = runtime.getStringLiteral(runtime[0].mInteger);
runtime.pop();
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 zRotDegrees = runtime[0].mFloat;
runtime.pop();
2022-09-22 21:26:05 +03:00
MWWorld::CellStore* store = nullptr;
2022-09-22 21:26:05 +03:00
try
{
store = &MWBase::Environment::get().getWorldModel()->getCell(cellName);
2022-09-22 21:26:05 +03:00
}
catch (std::exception&)
2022-09-22 21:26:05 +03:00
{
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)
2022-09-22 21:26:05 +03:00
{
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);
ref.getPtr().mRef->mData.mPhysicsPostponed = !ref.getPtr().getClass().isActor();
ref.getPtr().getCellRef().setPosition(pos);
2016-02-29 17:05:18 +01:00
MWWorld::Ptr placed = MWBase::Environment::get().getWorld()->placeObject(ref.getPtr(), store, pos);
placed.getClass().adjustPosition(placed, true);
}
2022-09-22 21:26:05 +03:00
}
};
class OpPlaceItem : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03: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));
runtime.pop();
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 zRotDegrees = runtime[0].mFloat;
runtime.pop();
2022-09-22 21:26:05 +03:00
2022-04-30 16:45:45 +02:00
MWWorld::Ptr player = MWMechanics::getPlayer();
2022-09-22 21:26:05 +03:00
if (!player.isInCell())
throw std::runtime_error("player not in a cell");
MWWorld::CellStore* store = nullptr;
if (player.getCell()->isExterior())
{
const ESM::ExteriorCellLocation cellIndex
= ESM::positionToExteriorCellLocation(x, y, player.getCell()->getCell()->getWorldSpace());
store = &MWBase::Environment::get().getWorldModel()->getExterior(cellIndex);
2022-09-22 21:26:05 +03:00
}
else
store = player.getCell();
2022-09-22 21:26:05 +03:00
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);
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);
2022-09-22 21:26:05 +03:00
}
};
template <class R, bool pc>
class OpPlaceAt : public Interpreter::Opcode0
2022-09-22 21:26:05 +03:00
{
public:
void execute(Interpreter::Runtime& runtime) override
2022-09-22 21:26:05 +03:00
{
MWWorld::Ptr actor = pc ? MWMechanics::getPlayer() : R()(runtime);
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));
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();
if (direction < 0 || direction > 3)
throw std::runtime_error("invalid direction");
if (count < 0)
throw std::runtime_error("count must be non-negative");
if (!actor.isInCell())
throw std::runtime_error("actor is not in a cell");
2012-09-17 13:36:48 +02:00
for (int i = 0; i < count; ++i)
2022-09-22 21:26:05 +03:00
{
// create item
2023-04-20 21:07:53 +02:00
MWWorld::ManualRef ref(*MWBase::Environment::get().getESMStore(), itemID, 1);
ref.getPtr().mRef->mData.mPhysicsPostponed = !ref.getPtr().getClass().isActor();
2022-09-22 21:26:05 +03:00
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->safePlaceObject(
ref.getPtr(), actor, actor.getCell(), direction, distance);
MWBase::Environment::get().getWorld()->scaleObject(ptr, actor.getCellRef().getScale());
}
2022-09-22 21:26:05 +03:00
}
};
2013-04-10 22:53:03 +02:00
template <class R>
class OpRotate : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2013-04-10 22:53:03 +02:00
{
2013-04-15 16:45:53 +02:00
const MWWorld::Ptr& ptr = R()(runtime);
2022-09-22 21:26:05 +03:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
2013-04-10 22:53:03 +02:00
runtime.pop();
Interpreter::Type_Float rotation
= osg::DegreesToRadians(runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
2013-04-10 22:53:03 +02:00
runtime.pop();
2022-09-22 21:26:05 +03:00
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;
2013-04-14 21:42:37 +02:00
else if (axis == "y")
rot.y() += rotation;
MWBase::Environment::get().getWorld()->rotateObject(ptr, rot);
2013-04-10 22:53:03 +02:00
}
};
2013-04-15 16:45:53 +02:00
template <class R>
class OpRotateWorld : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2013-04-15 16:45:53 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
2022-09-22 21:26:05 +03:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
2013-04-15 16:45:53 +02:00
runtime.pop();
Interpreter::Type_Float rotation
= osg::DegreesToRadians(runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
2013-04-15 16:45:53 +02:00
runtime.pop();
2022-09-22 21:26:05 +03:00
if (!ptr.getRefData().getBaseNode())
return;
2022-09-22 21:26:05 +03:00
// We can rotate actors only around Z axis
if (ptr.getClass().isActor() && (axis == "x" || axis == "y"))
return;
2022-09-22 21:26:05 +03:00
osg::Quat rot;
2013-04-15 16:45:53 +02:00
if (axis == "x")
rot = osg::Quat(rotation, -osg::X_AXIS);
2013-04-15 16:45:53 +02:00
else if (axis == "y")
rot = osg::Quat(rotation, -osg::Y_AXIS);
2013-04-15 16:45:53 +02:00
else if (axis == "z")
rot = osg::Quat(rotation, -osg::Z_AXIS);
2013-04-15 16:45:53 +02:00
else
return;
2022-09-22 21:26:05 +03:00
osg::Quat attitude = ptr.getRefData().getBaseNode()->getAttitude();
MWBase::Environment::get().getWorld()->rotateWorldObject(ptr, attitude * rot);
2013-04-15 16:45:53 +02:00
}
};
2013-04-26 02:02:51 +02:00
template <class R>
class OpSetAtStart : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2013-04-26 02:02:51 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
if (!ptr.isInCell())
return;
MWBase::Environment::get().getWorld()->rotateObject(
ptr, ptr.getCellRef().getPosition().asRotationVec3());
2013-04-26 02:02:51 +02: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
}
};
2013-04-26 17:28:19 +02:00
template <class R>
class OpMove : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2013-04-26 17:28:19 +02:00
{
const MWWorld::Ptr& ptr = R()(runtime);
if (!ptr.isInCell())
return;
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
2013-04-26 17:28:19 +02:00
runtime.pop();
Interpreter::Type_Float movement = (runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
runtime.pop();
2015-05-12 19:02:56 +02:00
osg::Vec3f posChange;
2013-04-26 17:28:19 +02:00
if (axis == "x")
{
2015-05-12 19:02:56 +02:00
posChange = osg::Vec3f(movement, 0, 0);
2013-04-26 17:28:19 +02:00
}
else if (axis == "y")
{
2015-05-12 19:02:56 +02:00
posChange = osg::Vec3f(0, movement, 0);
2013-04-26 17:28:19 +02:00
}
else if (axis == "z")
{
2015-05-12 19:02:56 +02:00
posChange = osg::Vec3f(0, 0, movement);
2013-04-26 17:28:19 +02:00
}
else
return;
2013-04-26 17:28:19 +02:00
2015-05-12 19:02:56 +02:00
// is it correct that disabled objects can't be Move-d?
if (!ptr.getRefData().getBaseNode())
return;
2015-05-12 19:02:56 +02:00
osg::Vec3f diff = ptr.getRefData().getBaseNode()->getAttitude() * posChange;
// 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())
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
2013-04-26 17:28:19 +02:00
}
};
template <class R>
class OpMoveWorld : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
2013-04-26 17:28:19 +02:00
{
MWWorld::Ptr ptr = R()(runtime);
2022-09-22 21:26:05 +03:00
if (!ptr.isInCell())
return;
2022-09-22 21:26:05 +03:00
std::string_view axis = runtime.getStringLiteral(runtime[0].mInteger);
2013-04-26 17:28:19 +02:00
runtime.pop();
Interpreter::Type_Float movement = (runtime[0].mFloat * MWBase::Environment::get().getFrameDuration());
runtime.pop();
2022-09-22 21:26:05 +03:00
osg::Vec3f diff;
2022-09-22 21:26:05 +03:00
2013-04-26 17:28:19 +02:00
if (axis == "x")
diff.x() = movement;
2013-04-26 17:28:19 +02:00
else if (axis == "y")
diff.y() = movement;
2013-04-26 17:28:19 +02:00
else if (axis == "z")
diff.z() = movement;
2013-04-26 17:28:19 +02:00
else
return;
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())
.updatePtr(ptr, MWBase::Environment::get().getWorld()->moveObjectBy(ptr, diff, false));
2013-04-26 17:28:19 +02:00
}
};
class OpResetActors : public Interpreter::Opcode0
{
public:
void execute(Interpreter::Runtime& runtime) override
{
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:
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
}
};
2012-07-09 18:47:59 +02:00
void installOpcodes(Interpreter::Interpreter& interpreter)
{
2022-01-27 19:18:57 +00:00
interpreter.installSegment5<OpGetDistance<ImplicitRef>>(Compiler::Transformation::opcodeGetDistance);
interpreter.installSegment5<OpGetDistance<ExplicitRef>>(
Compiler::Transformation::opcodeGetDistanceExplicit);
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);
interpreter.installSegment5<OpGetStartingPos<ExplicitRef>>(
Compiler::Transformation::opcodeGetStartingPosExplicit);
interpreter.installSegment5<OpPosition<ImplicitRef>>(Compiler::Transformation::opcodePosition);
interpreter.installSegment5<OpPosition<ExplicitRef>>(Compiler::Transformation::opcodePositionExplicit);
interpreter.installSegment5<OpPositionCell<ImplicitRef>>(Compiler::Transformation::opcodePositionCell);
interpreter.installSegment5<OpPositionCell<ExplicitRef>>(
Compiler::Transformation::opcodePositionCellExplicit);
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);
interpreter.installSegment5<OpPlaceAt<ExplicitRef, false>>(
Compiler::Transformation::opcodePlaceAtMeExplicit);
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);
interpreter.installSegment5<OpRotateWorld<ExplicitRef>>(
Compiler::Transformation::opcodeRotateWorldExplicit);
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);
interpreter.installSegment5<OpGetStartingAngle<ImplicitRef>>(
Compiler::Transformation::opcodeGetStartingAngle);
interpreter.installSegment5<OpGetStartingAngle<ExplicitRef>>(
Compiler::Transformation::opcodeGetStartingAngleExplicit);
interpreter.installSegment5<OpResetActors>(Compiler::Transformation::opcodeResetActors);
interpreter.installSegment5<OpFixme>(Compiler::Transformation::opcodeFixme);
2012-07-09 18:47:59 +02:00
}
}
}