1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-26 18:35:20 +00:00

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

374 lines
14 KiB
C++
Raw Normal View History

2010-08-03 15:24:44 +02:00
#include "door.hpp"
#include <MyGUI_TextIterator.h>
#include <components/esm3/doorstate.hpp>
#include <components/esm3/loaddoor.hpp>
#include <components/esm3/loadmgef.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
2010-08-03 15:24:44 +02:00
#include "../mwbase/environment.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwphysics/physicssystem.hpp"
2013-04-28 14:59:15 +02:00
#include "../mwworld/actiondoor.hpp"
#include "../mwworld/actionteleport.hpp"
#include "../mwworld/actiontrap.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/cellutils.hpp"
#include "../mwworld/containerstore.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwworld/esmstore.hpp"
2012-11-17 18:17:08 +01:00
#include "../mwworld/failedaction.hpp"
2010-08-03 17:11:41 +02:00
#include "../mwworld/ptr.hpp"
#include "../mwgui/tooltips.hpp"
#include "../mwgui/ustring.hpp"
#include "../mwrender/animation.hpp"
#include "../mwrender/objects.hpp"
#include "../mwrender/renderinginterface.hpp"
#include "../mwrender/vismask.hpp"
2015-08-21 21:12:39 +12:00
#include "../mwmechanics/actorutil.hpp"
#include "classmodel.hpp"
namespace MWClass
{
class DoorCustomData : public MWWorld::TypedCustomData<DoorCustomData>
{
public:
2019-12-21 14:35:08 +04:00
MWWorld::DoorState mDoorState = MWWorld::DoorState::Idle;
DoorCustomData& asDoorCustomData() override { return *this; }
const DoorCustomData& asDoorCustomData() const override { return *this; }
};
2022-04-04 02:44:53 +02:00
Door::Door()
: MWWorld::RegisteredClass<Door>(ESM::Door::sRecordId)
{
}
void Door::insertObjectRendering(
const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const
{
if (!model.empty())
{
renderingInterface.getObjects().insertModel(ptr, model);
ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static);
}
}
void Door::insertObject(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
MWPhysics::PhysicsSystem& physics) const
2011-11-11 23:01:12 -05:00
{
insertObjectPhysics(ptr, model, rotation, physics);
// Resume the door's opening/closing animation if it wasn't finished
if (ptr.getRefData().getCustomData())
{
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
2019-08-25 15:20:14 +02:00
if (customData.mDoorState != MWWorld::DoorState::Idle)
{
MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState);
}
}
}
void Door::insertObjectPhysics(const MWWorld::Ptr& ptr, const std::string& model, const osg::Quat& rotation,
MWPhysics::PhysicsSystem& physics) const
{
physics.addObject(ptr, model, rotation, MWPhysics::CollisionType_Door);
}
bool Door::isDoor() const
{
return true;
}
bool Door::useAnim() const
{
return true;
2012-07-24 20:22:11 +04:00
}
2012-07-27 12:00:10 +02:00
2015-12-18 15:51:05 +01:00
std::string Door::getModel(const MWWorld::ConstPtr& ptr) const
2012-07-24 20:22:11 +04:00
{
return getClassModel<ESM::Door>(ptr);
2011-11-11 23:01:12 -05:00
}
2022-08-16 21:15:03 +02:00
std::string_view Door::getName(const MWWorld::ConstPtr& ptr) const
2010-08-03 17:11:41 +02:00
{
const MWWorld::LiveCellRef<ESM::Door>* ref = ptr.get<ESM::Door>();
const std::string& name = ref->mBase->mName;
2010-08-03 17:11:41 +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
return !name.empty() ? name : ref->mBase->mId.getRefIdString();
2010-08-03 17:11:41 +02:00
}
std::unique_ptr<MWWorld::Action> Door::activate(const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const
{
MWWorld::LiveCellRef<ESM::Door>* ref = ptr.get<ESM::Door>();
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& openSound = ref->mBase->mOpenSound;
const ESM::RefId& closeSound = ref->mBase->mCloseSound;
const ESM::RefId lockedSound = ESM::RefId::stringRefId("LockedDoor");
2012-02-27 09:39:35 +02:00
// FIXME: If NPC activate teleporting door, it can lead to crash due to iterator invalidation in the Actors
2018-06-17 10:13:03 +02:00
// update. Make such activation a no-op for now, like how it is in the vanilla game.
if (actor != MWMechanics::getPlayer() && ptr.getCellRef().getTeleport())
{
2022-08-24 20:38:52 +02:00
std::unique_ptr<MWWorld::Action> action = std::make_unique<MWWorld::FailedAction>(std::string_view{}, ptr);
action->setSound(lockedSound);
return action;
}
// make door glow if player activates it with telekinesis
if (actor == MWMechanics::getPlayer()
&& MWBase::Environment::get().getWorld()->getDistanceToFacedObject()
> MWBase::Environment::get().getWorld()->getMaxActivationDistance())
{
MWRender::Animation* animation = MWBase::Environment::get().getWorld()->getAnimation(ptr);
if (animation)
{
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
int index = ESM::MagicEffect::effectStringToId("sEffectTelekinesis");
const ESM::MagicEffect* effect = store.get<ESM::MagicEffect>().find(index);
animation->addSpellCastGlow(
effect, 1); // 1 second glow to match the time taken for a door opening or closing
}
}
2022-08-24 20:38:52 +02:00
MWWorld::ContainerStore& invStore = actor.getClass().getContainerStore(actor);
bool isLocked = ptr.getCellRef().getLockLevel() > 0;
bool isTrapped = !ptr.getCellRef().getTrap().empty();
bool hasKey = false;
std::string_view keyName;
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& keyId = ptr.getCellRef().getKey();
2017-06-10 22:33:14 +04:00
if (!keyId.empty())
{
MWWorld::Ptr keyPtr = invStore.search(keyId);
if (!keyPtr.isEmpty())
{
hasKey = true;
keyName = keyPtr.getClass().getName(keyPtr);
}
}
if (isLocked && hasKey)
2012-02-27 16:59:45 +02:00
{
2015-08-21 21:12:39 +12:00
if (actor == MWMechanics::getPlayer())
2022-08-24 20:38:52 +02:00
MWBase::Environment::get().getWindowManager()->messageBox(std::string{ keyName } + " #{sKeyUsed}");
ptr.getCellRef().unlock(); // Call the function here. because that makes sense.
// using a key disarms the trap
if (isTrapped)
{
ptr.getCellRef().setTrap(ESM::RefId());
MWBase::Environment::get().getSoundManager()->playSound3D(
ptr, ESM::RefId::stringRefId("Disarm Trap"), 1.0f, 1.0f);
isTrapped = false;
}
2012-02-27 16:59:45 +02:00
}
if (!isLocked || hasKey)
{
if (isTrapped)
{
// Trap activation
2022-05-29 13:24:48 +02:00
std::unique_ptr<MWWorld::Action> action
= std::make_unique<MWWorld::ActionTrap>(ptr.getCellRef().getTrap(), ptr);
action->setSound(ESM::RefId::stringRefId("Disarm Trap Fail"));
return action;
}
if (ptr.getCellRef().getTeleport())
{
if (actor == MWMechanics::getPlayer()
&& MWBase::Environment::get().getWorld()->getDistanceToFacedObject()
> MWBase::Environment::get().getWorld()->getMaxActivationDistance())
{
// player activated teleport door with telekinesis
2022-05-29 13:24:48 +02:00
return std::make_unique<MWWorld::FailedAction>();
}
else
{
2022-05-29 13:24:48 +02:00
std::unique_ptr<MWWorld::Action> action = std::make_unique<MWWorld::ActionTeleport>(
ptr.getCellRef().getDestCell(), ptr.getCellRef().getDoorDest(), true);
action->setSound(openSound);
return action;
}
}
else
{
// animated door
2022-05-29 13:24:48 +02:00
std::unique_ptr<MWWorld::Action> action = std::make_unique<MWWorld::ActionDoor>(ptr);
2019-08-25 15:20:14 +02:00
const auto doorState = getDoorState(ptr);
bool opening = true;
float doorRot = ptr.getRefData().getPosition().rot[2] - ptr.getCellRef().getPosition().rot[2];
2019-08-25 15:20:14 +02:00
if (doorState == MWWorld::DoorState::Opening)
opening = false;
2019-08-25 15:20:14 +02:00
if (doorState == MWWorld::DoorState::Idle && doorRot != 0)
opening = false;
if (opening)
{
MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, closeSound, 0.5f);
// Doors rotate at 90 degrees per second, so start the sound at
// where it would be at the current rotation.
float offset = doorRot / (osg::PI * 0.5f);
action->setSoundOffset(offset);
2013-04-28 14:59:15 +02:00
action->setSound(openSound);
}
2013-04-28 14:59:15 +02:00
else
{
MWBase::Environment::get().getSoundManager()->fadeOutSound3D(ptr, openSound, 0.5f);
float offset = 1.0f - doorRot / (osg::PI * 0.5f);
action->setSoundOffset(std::max(offset, 0.0f));
2013-04-28 14:59:15 +02:00
action->setSound(closeSound);
}
return action;
}
}
else
{
// locked, and we can't open.
2022-08-24 20:38:52 +02:00
std::unique_ptr<MWWorld::Action> action = std::make_unique<MWWorld::FailedAction>(std::string_view{}, ptr);
action->setSound(lockedSound);
return action;
}
}
2015-12-18 16:50:32 +01:00
bool Door::canLock(const MWWorld::ConstPtr& ptr) const
{
return true;
}
bool Door::allowTelekinesis(const MWWorld::ConstPtr& ptr) const
{
if (ptr.getCellRef().getTeleport() && ptr.getCellRef().getLockLevel() <= 0
&& ptr.getCellRef().getTrap().empty())
return false;
else
return true;
}
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& Door::getScript(const MWWorld::ConstPtr& ptr) const
{
2015-12-18 00:12:03 +01:00
const MWWorld::LiveCellRef<ESM::Door>* ref = ptr.get<ESM::Door>();
2012-11-05 16:07:59 +04:00
return ref->mBase->mScript;
}
2015-12-19 16:29:07 +01:00
MWGui::ToolTipInfo Door::getToolTipInfo(const MWWorld::ConstPtr& ptr, int count) const
{
const MWWorld::LiveCellRef<ESM::Door>* ref = ptr.get<ESM::Door>();
MWGui::ToolTipInfo info;
2022-08-16 21:15:03 +02:00
std::string_view name = getName(ptr);
info.caption = MyGUI::TextIterator::toTagsString(MWGui::toUString(name));
std::string text;
if (ptr.getCellRef().getTeleport())
{
2012-09-22 21:35:57 +02:00
text += "\n#{sTo}";
2012-12-23 23:23:24 +04:00
text += "\n" + getDestination(*ref);
}
int lockLevel = ptr.getCellRef().getLockLevel();
if (lockLevel > 0 && lockLevel != ESM::UnbreakableLock)
text += "\n#{sLockLevel}: " + MWGui::ToolTips::toString(ptr.getCellRef().getLockLevel());
else if (ptr.getCellRef().getLockLevel() < 0)
text += "\n#{sUnlocked}";
2022-08-16 21:15:03 +02:00
if (!ptr.getCellRef().getTrap().empty())
2012-09-22 21:35:57 +02:00
text += "\n#{sTrapped}";
if (MWBase::Environment::get().getWindowManager()->getFullHelp())
2014-07-11 11:57:21 +02:00
{
text += MWGui::ToolTips::getCellRefString(ptr.getCellRef());
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
text += MWGui::ToolTips::getMiscString(ref->mBase->mScript.getRefIdString(), "Script");
2014-07-11 11:57:21 +02:00
}
info.text = text;
return info;
}
2012-12-23 23:23:24 +04:00
std::string Door::getDestination(const MWWorld::LiveCellRef<ESM::Door>& door)
{
2023-01-19 17:31:45 +01:00
std::string_view dest = door.mRef.getDestCell();
if (dest.empty())
2012-12-23 23:23:24 +04:00
{
// door leads to exterior, use cell name (if any), otherwise translated region name
auto world = MWBase::Environment::get().getWorld();
const osg::Vec2i index
= MWWorld::positionToCellIndex(door.mRef.getDoorDest().pos[0], door.mRef.getDoorDest().pos[1]);
const ESM::Cell* cell = world->getStore().get<ESM::Cell>().search(index.x(), index.y());
dest = world->getCellName(cell);
2012-12-23 23:23:24 +04:00
}
return "#{sCell=" + std::string{ dest } + "}";
2012-12-23 23:23:24 +04:00
}
2015-12-18 16:24:24 +01:00
MWWorld::Ptr Door::copyToCellImpl(const MWWorld::ConstPtr& ptr, MWWorld::CellStore& cell) const
{
2015-12-18 16:24:24 +01:00
const MWWorld::LiveCellRef<ESM::Door>* ref = ptr.get<ESM::Door>();
return MWWorld::Ptr(cell.insert(ref), &cell);
}
void Door::ensureCustomData(const MWWorld::Ptr& ptr) const
{
if (!ptr.getRefData().getCustomData())
{
ptr.getRefData().setCustomData(std::make_unique<DoorCustomData>());
}
}
2019-08-25 15:20:14 +02:00
MWWorld::DoorState Door::getDoorState(const MWWorld::ConstPtr& ptr) const
{
2015-12-19 15:57:37 +01:00
if (!ptr.getRefData().getCustomData())
2019-08-25 15:20:14 +02:00
return MWWorld::DoorState::Idle;
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
return customData.mDoorState;
}
2019-08-25 15:20:14 +02:00
void Door::setDoorState(const MWWorld::Ptr& ptr, MWWorld::DoorState state) const
{
if (ptr.getCellRef().getTeleport())
throw std::runtime_error("load doors can't be moved");
ensureCustomData(ptr);
DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
customData.mDoorState = state;
}
void Door::readAdditionalState(const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const
{
if (!state.mHasCustomState)
return;
ensureCustomData(ptr);
DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
const ESM::DoorState& doorState = state.asDoorState();
customData.mDoorState = MWWorld::DoorState(doorState.mDoorState);
}
void Door::writeAdditionalState(const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const
{
if (!ptr.getRefData().getCustomData())
{
state.mHasCustomState = false;
return;
}
const DoorCustomData& customData = ptr.getRefData().getCustomData()->asDoorCustomData();
ESM::DoorState& doorState = state.asDoorState();
doorState.mDoorState = int(customData.mDoorState);
}
2010-08-03 15:24:44 +02:00
}