1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-04 03:40:14 +00:00
OpenMW/apps/openmw/mwlua/localscripts.cpp

194 lines
9.0 KiB
C++
Raw Normal View History

2020-12-18 23:21:10 +01:00
#include "localscripts.hpp"
2022-01-23 20:49:42 +01:00
#include <components/esm3/loadcell.hpp>
2021-01-29 01:54:54 +01:00
#include "../mwworld/ptr.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/aisequence.hpp"
#include "../mwmechanics/aicombat.hpp"
2022-01-23 20:49:42 +01:00
#include "../mwmechanics/aiescort.hpp"
#include "../mwmechanics/aifollow.hpp"
#include "../mwmechanics/aipursue.hpp"
#include "../mwmechanics/aitravel.hpp"
#include "../mwmechanics/aiwander.hpp"
#include "../mwmechanics/aipackage.hpp"
#include "../mwmechanics/creaturestats.hpp"
2021-01-29 01:54:54 +01:00
2021-03-28 17:44:08 +02:00
#include "luamanagerimp.hpp"
2020-12-18 23:21:10 +01:00
namespace sol
{
template <>
struct is_automagical<MWBase::LuaManager::ActorControls> : std::false_type {};
template <>
struct is_automagical<MWLua::LocalScripts::SelfObject> : std::false_type {};
}
namespace MWLua
{
void LocalScripts::initializeSelfPackage(const Context& context)
{
using ActorControls = MWBase::LuaManager::ActorControls;
sol::usertype<ActorControls> controls = context.mLua->sol().new_usertype<ActorControls>("ActorControls");
#define CONTROL(TYPE, FIELD) sol::property([](const ActorControls& c) { return c.FIELD; },\
[](ActorControls& c, const TYPE& v) { c.FIELD = v; c.mChanged = true; })
controls["movement"] = CONTROL(float, mMovement);
controls["sideMovement"] = CONTROL(float, mSideMovement);
controls["pitchChange"] = CONTROL(float, mPitchChange);
controls["yawChange"] = CONTROL(float, mYawChange);
controls["run"] = CONTROL(bool, mRun);
controls["jump"] = CONTROL(bool, mJump);
controls["use"] = CONTROL(int, mUse);
#undef CONTROL
2020-12-18 23:21:10 +01:00
sol::usertype<SelfObject> selfAPI =
context.mLua->sol().new_usertype<SelfObject>("SelfObject", sol::base_classes, sol::bases<LObject, Object>());
2020-12-18 23:21:10 +01:00
selfAPI[sol::meta_function::to_string] = [](SelfObject& self) { return "openmw.self[" + self.toString() + "]"; };
selfAPI["object"] = sol::readonly_property([](SelfObject& self) -> LObject { return LObject(self); });
selfAPI["controls"] = sol::readonly_property([](SelfObject& self) { return &self.mControls; });
selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; };
2021-04-23 02:49:12 +02:00
selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; };
2022-01-23 20:49:42 +01:00
using AiPackage = MWMechanics::AiPackage;
sol::usertype<AiPackage> aiPackage = context.mLua->sol().new_usertype<AiPackage>("AiPackage");
aiPackage["type"] = sol::readonly_property([](const AiPackage& p) -> std::string_view
{
switch (p.getTypeId())
{
case MWMechanics::AiPackageTypeId::Wander: return "Wander";
case MWMechanics::AiPackageTypeId::Travel: return "Travel";
case MWMechanics::AiPackageTypeId::Escort: return "Escort";
case MWMechanics::AiPackageTypeId::Follow: return "Follow";
case MWMechanics::AiPackageTypeId::Activate: return "Activate";
case MWMechanics::AiPackageTypeId::Combat: return "Combat";
case MWMechanics::AiPackageTypeId::Pursue: return "Pursue";
case MWMechanics::AiPackageTypeId::AvoidDoor: return "AvoidDoor";
case MWMechanics::AiPackageTypeId::Face: return "Face";
case MWMechanics::AiPackageTypeId::Breathe: return "Breathe";
case MWMechanics::AiPackageTypeId::Cast: return "Cast";
default: return "Unknown";
}
});
aiPackage["target"] = sol::readonly_property([worldView=context.mWorldView](const AiPackage& p) -> sol::optional<LObject>
{
MWWorld::Ptr target = p.getTarget();
if (target.isEmpty())
return sol::nullopt;
else
return LObject(getId(target), worldView->getObjectRegistry());
});
aiPackage["sideWithTarget"] = sol::readonly_property([](const AiPackage& p) { return p.sideWithTarget(); });
2022-06-21 21:06:37 +02:00
aiPackage["destPosition"] = sol::readonly_property([](const AiPackage& p) { return p.getDestination(); });
2022-01-23 20:49:42 +01:00
selfAPI["_getActiveAiPackage"] = [](SelfObject& self) -> sol::optional<std::shared_ptr<AiPackage>>
2021-01-29 01:54:54 +01:00
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
2022-01-23 20:49:42 +01:00
if (ai.isEmpty())
return sol::nullopt;
2021-01-29 01:54:54 +01:00
else
2022-01-23 20:49:42 +01:00
return *ai.begin();
2021-01-29 01:54:54 +01:00
};
2022-01-23 20:49:42 +01:00
selfAPI["_iterateAndFilterAiSequence"] = [](SelfObject& self, sol::function callback)
2021-01-29 01:54:54 +01:00
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
2022-02-12 23:50:41 +00:00
ai.erasePackagesIf([&](auto& entry)
2022-01-23 20:49:42 +01:00
{
2022-02-12 23:50:41 +00:00
bool keep = LuaUtil::call(callback, entry).template get<bool>();
return !keep;
});
2021-01-29 01:54:54 +01:00
};
2022-01-23 20:49:42 +01:00
selfAPI["_startAiCombat"] = [](SelfObject& self, const LObject& target)
2021-01-29 01:54:54 +01:00
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
ai.stack(MWMechanics::AiCombat(target.ptr()), ptr);
};
2022-01-23 20:49:42 +01:00
selfAPI["_startAiPursue"] = [](SelfObject& self, const LObject& target)
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
ai.stack(MWMechanics::AiPursue(target.ptr()), ptr);
};
selfAPI["_startAiFollow"] = [](SelfObject& self, const LObject& target)
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
ai.stack(MWMechanics::AiFollow(target.ptr()), ptr);
};
selfAPI["_startAiEscort"] = [](SelfObject& self, const LObject& target, LCell cell,
float duration, const osg::Vec3f& dest)
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
// TODO: change AiEscort implementation to accept ptr instead of a non-unique refId.
const std::string& refId = target.ptr().getCellRef().getRefId();
int gameHoursDuration = static_cast<int>(std::ceil(duration / 3600.0));
const ESM::Cell* esmCell = cell.mStore->getCell();
if (esmCell->isExterior())
ai.stack(MWMechanics::AiEscort(refId, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr);
else
ai.stack(MWMechanics::AiEscort(refId, esmCell->mName, gameHoursDuration, dest.x(), dest.y(), dest.z(), false), ptr);
};
selfAPI["_startAiWander"] = [](SelfObject& self, int distance, float duration)
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
int gameHoursDuration = static_cast<int>(std::ceil(duration / 3600.0));
ai.stack(MWMechanics::AiWander(distance, gameHoursDuration, 0, {}, false), ptr);
};
selfAPI["_startAiTravel"] = [](SelfObject& self, const osg::Vec3f& target)
{
const MWWorld::Ptr& ptr = self.ptr();
MWMechanics::AiSequence& ai = ptr.getClass().getCreatureStats(ptr).getAiSequence();
ai.stack(MWMechanics::AiTravel(target.x(), target.y(), target.z(), false), ptr);
};
2020-12-18 23:21:10 +01:00
}
2022-05-20 21:47:13 +02:00
LocalScripts::LocalScripts(LuaUtil::LuaState* lua, const LObject& obj)
: LuaUtil::ScriptsContainer(lua, "L" + idToString(obj.id())), mData(obj)
2020-12-18 23:21:10 +01:00
{
this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData));
registerEngineHandlers({&mOnActiveHandlers, &mOnInactiveHandlers, &mOnConsumeHandlers, &mOnActivatedHandlers});
}
void LocalScripts::receiveEngineEvent(const EngineEvent& event)
{
std::visit([this](auto&& arg)
{
using EventT = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<EventT, OnActive>)
{
mData.mIsActive = true;
callEngineHandlers(mOnActiveHandlers);
}
else if constexpr (std::is_same_v<EventT, OnInactive>)
{
mData.mIsActive = false;
callEngineHandlers(mOnInactiveHandlers);
}
else if constexpr (std::is_same_v<EventT, OnActivated>)
{
callEngineHandlers(mOnActivatedHandlers, arg.mActivatingActor);
}
else
{
static_assert(std::is_same_v<EventT, OnConsume>);
callEngineHandlers(mOnConsumeHandlers, arg.mConsumable);
}
}, event);
2020-12-18 23:21:10 +01:00
}
2022-03-25 20:03:13 +00:00
void LocalScripts::applyStatsCache()
{
const auto& ptr = mData.ptr();
for (auto& [stat, value] : mData.mStatsCache)
stat(ptr, value);
mData.mStatsCache.clear();
}
2020-12-18 23:21:10 +01:00
}