1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 12:35:46 +00:00
OpenMW/apps/openmw/mwlua/actions.cpp

125 lines
5.1 KiB
C++
Raw Normal View History

2021-03-28 17:44:08 +02:00
#include "actions.hpp"
#include <components/debug/debuglog.hpp>
2021-04-17 11:50:20 +02:00
#include "../mwworld/cellstore.hpp"
2021-03-28 17:44:08 +02:00
#include "../mwworld/class.hpp"
#include "../mwworld/inventorystore.hpp"
#include "../mwworld/player.hpp"
namespace MWLua
{
void TeleportAction::apply(WorldView& worldView) const
{
2021-04-17 11:50:20 +02:00
MWWorld::CellStore* cell = worldView.findCell(mCell, mPos);
2021-03-28 17:44:08 +02:00
if (!cell)
{
Log(Debug::Error) << "LuaManager::applyTeleport -> cell not found: '" << mCell << "'";
return;
}
2021-04-17 11:50:20 +02:00
MWBase::World* world = MWBase::Environment::get().getWorld();
2021-03-28 17:44:08 +02:00
MWWorld::Ptr obj = worldView.getObjectRegistry()->getPtr(mObject, false);
const MWWorld::Class& cls = obj.getClass();
bool isPlayer = obj == world->getPlayerPtr();
if (cls.isActor())
cls.getCreatureStats(obj).land(isPlayer);
if (isPlayer)
{
ESM::Position esmPos;
static_assert(sizeof(esmPos) == sizeof(osg::Vec3f) * 2);
std::memcpy(esmPos.pos, &mPos, sizeof(osg::Vec3f));
std::memcpy(esmPos.rot, &mRot, sizeof(osg::Vec3f));
world->getPlayer().setTeleported(true);
2021-04-17 11:50:20 +02:00
if (cell->isExterior())
2021-03-28 17:44:08 +02:00
world->changeToExteriorCell(esmPos, true);
else
world->changeToInteriorCell(mCell, esmPos, true);
}
else
{
MWWorld::Ptr newObj = world->moveObject(obj, cell, mPos.x(), mPos.y(), mPos.z());
world->rotateObject(newObj, mRot.x(), mRot.y(), mRot.z());
}
}
void SetEquipmentAction::apply(WorldView& worldView) const
{
MWWorld::Ptr actor = worldView.getObjectRegistry()->getPtr(mActor, false);
MWWorld::InventoryStore& store = actor.getClass().getInventoryStore(actor);
std::array<bool, MWWorld::InventoryStore::Slots> usedSlots;
std::fill(usedSlots.begin(), usedSlots.end(), false);
constexpr int anySlot = -1;
2021-04-23 02:49:12 +02:00
auto tryEquipToSlot = [&actor, &store, &usedSlots, &worldView, anySlot](int slot, const Item& item) -> bool
2021-03-28 17:44:08 +02:00
{
auto old_it = slot != anySlot ? store.getSlot(slot) : store.end();
MWWorld::Ptr itemPtr;
if (std::holds_alternative<ObjectId>(item))
{
itemPtr = worldView.getObjectRegistry()->getPtr(std::get<ObjectId>(item), false);
if (old_it != store.end() && *old_it == itemPtr)
return true; // already equipped
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0 ||
itemPtr.getContainerStore() != static_cast<const MWWorld::ContainerStore*>(&store))
{
Log(Debug::Warning) << "Object" << idToString(std::get<ObjectId>(item)) << " is not in inventory";
return false;
}
}
else
{
const std::string& recordId = std::get<std::string>(item);
if (old_it != store.end() && *old_it->getCellRef().getRefIdPtr() == recordId)
return true; // already equipped
itemPtr = store.search(recordId);
if (itemPtr.isEmpty() || itemPtr.getRefData().getCount() == 0)
{
Log(Debug::Warning) << "There is no object with recordId='" << recordId << "' in inventory";
return false;
}
}
auto [allowedSlots, _] = itemPtr.getClass().getEquipmentSlots(itemPtr);
2021-04-23 02:49:12 +02:00
bool requestedSlotIsAllowed = std::find(allowedSlots.begin(), allowedSlots.end(), slot) != allowedSlots.end();
2021-03-28 17:44:08 +02:00
if (!requestedSlotIsAllowed)
{
2021-04-23 02:49:12 +02:00
auto firstAllowed = std::find_if(allowedSlots.begin(), allowedSlots.end(), [&](int s) { return !usedSlots[s]; });
if (firstAllowed == allowedSlots.end())
2021-03-28 17:44:08 +02:00
{
Log(Debug::Warning) << "No suitable slot for " << ptrToString(itemPtr);
return false;
}
2021-04-23 02:49:12 +02:00
slot = *firstAllowed;
2021-03-28 17:44:08 +02:00
}
// TODO: Refactor InventoryStore to accept Ptr and get rid of this linear search.
MWWorld::ContainerStoreIterator it = std::find(store.begin(), store.end(), itemPtr);
if (it == store.end()) // should never happen
throw std::logic_error("Item not found in container");
store.equip(slot, it, actor);
return requestedSlotIsAllowed; // return true if equipped to requested slot and false if slot was changed
};
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
auto old_it = store.getSlot(slot);
auto new_it = mEquipment.find(slot);
if (new_it == mEquipment.end())
{
if (old_it != store.end())
store.unequipSlot(slot, actor);
continue;
}
if (tryEquipToSlot(slot, new_it->second))
usedSlots[slot] = true;
}
2021-04-23 02:49:12 +02:00
for (const auto& [slot, item] : mEquipment)
2021-03-28 17:44:08 +02:00
if (slot >= MWWorld::InventoryStore::Slots)
tryEquipToSlot(anySlot, item);
}
}