From a8f76260bc0519a9ba217d74da2523469ddee0c7 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 18 Apr 2021 22:09:01 +0200 Subject: [PATCH] A possibility to view actor controls from lua scripts without disabling AI. --- apps/openmw/mwbase/luamanager.hpp | 3 +- apps/openmw/mwlua/localscripts.cpp | 2 ++ apps/openmw/mwlua/localscripts.hpp | 2 +- apps/openmw/mwlua/luamanagerimp.cpp | 2 +- apps/openmw/mwlua/luamanagerimp.hpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 51 +++++++++++++++++------------ 6 files changed, 37 insertions(+), 25 deletions(-) diff --git a/apps/openmw/mwbase/luamanager.hpp b/apps/openmw/mwbase/luamanager.hpp index b9109518cc..0d6aee38f1 100644 --- a/apps/openmw/mwbase/luamanager.hpp +++ b/apps/openmw/mwbase/luamanager.hpp @@ -34,6 +34,7 @@ namespace MWBase virtual void keyPressed(const SDL_KeyboardEvent &arg) = 0; struct ActorControls { + bool disableAI; bool controlledFromLua; bool jump; @@ -43,7 +44,7 @@ namespace MWBase float turn; }; - virtual const ActorControls* getActorControls(const MWWorld::Ptr&) const = 0; + virtual ActorControls* getActorControls(const MWWorld::Ptr&) const = 0; virtual void clear() = 0; virtual void setupPlayer(const MWWorld::Ptr&) = 0; diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 4b556faa4d..5b5347af03 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -35,6 +35,7 @@ namespace MWLua selfAPI["controls"] = sol::readonly_property([](SelfObject& self) { return &self.mControls; }); selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; }; selfAPI["setDirectControl"] = [](SelfObject& self, bool v) { self.mControls.controlledFromLua = v; }; + selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.disableAI = !v; }; selfAPI["setEquipment"] = [manager=context.mLuaManager](const SelfObject& obj, sol::table equipment) { if (!obj.ptr().getClass().hasInventoryStore(obj.ptr())) @@ -87,6 +88,7 @@ namespace MWLua : LuaUtil::ScriptsContainer(lua, "L" + idToString(obj.id())), mData(obj) { mData.mControls.controlledFromLua = false; + mData.mControls.disableAI = false; this->addPackage("openmw.self", sol::make_object(lua->sol(), &mData)); registerEngineHandlers({&mOnActiveHandlers, &mOnInactiveHandlers}); } diff --git a/apps/openmw/mwlua/localscripts.hpp b/apps/openmw/mwlua/localscripts.hpp index a738dfede5..40bff371a1 100644 --- a/apps/openmw/mwlua/localscripts.hpp +++ b/apps/openmw/mwlua/localscripts.hpp @@ -22,7 +22,7 @@ namespace MWLua static std::unique_ptr create(LuaUtil::LuaState* lua, const LObject& obj); static void initializeSelfPackage(const Context&); - const MWBase::LuaManager::ActorControls* getActorControls() const { return &mData.mControls; } + MWBase::LuaManager::ActorControls* getActorControls() { return &mData.mControls; } struct SelfObject : public LObject { diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 09b3eb6e13..15e45eba1a 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -260,7 +260,7 @@ namespace MWLua mKeyPressEvents.push_back(arg.keysym); } - const MWBase::LuaManager::ActorControls* LuaManager::getActorControls(const MWWorld::Ptr& ptr) const + MWBase::LuaManager::ActorControls* LuaManager::getActorControls(const MWWorld::Ptr& ptr) const { LocalScripts* localScripts = ptr.getRefData().getLuaScripts(); if (!localScripts) diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 53f2955675..c0b08ee546 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -42,7 +42,7 @@ namespace MWLua void objectRemovedFromScene(const MWWorld::Ptr& ptr) override; void keyPressed(const SDL_KeyboardEvent &arg) override; - const MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override; + MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override; void clear() override; // should be called before loading game or starting a new game to reset internal state. void setupPlayer(const MWWorld::Ptr& ptr) override; // Should be called once after each "clear". diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9d3f16c31c..97d95251a4 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1962,6 +1962,8 @@ namespace MWMechanics { bool isPlayer = iter->first == player; CharacterController* ctrl = iter->second->getCharacterController(); + MWBase::LuaManager::ActorControls* luaControls = + MWBase::Environment::get().getLuaManager()->getActorControls(iter->first); float distSqr = (playerPos - iter->first.getRefData().getPosition().asVec3()).length2(); // AI processing is only done within given distance to the player. @@ -2010,25 +2012,6 @@ namespace MWMechanics return; // for now abort update of the old cell when cell changes by teleportation magic effect // a better solution might be to apply cell changes at the end of the frame } - bool controlledFromLua; - { - const MWBase::LuaManager::ActorControls* luaControls = - MWBase::Environment::get().getLuaManager()->getActorControls(iter->first); - controlledFromLua = luaControls && luaControls->controlledFromLua; - if (controlledFromLua && isConscious(iter->first)) - { - Movement& mov = iter->first.getClass().getMovementSettings(iter->first); - mov.mPosition[0] = luaControls->sideMovement; - mov.mPosition[1] = luaControls->movement; - mov.mPosition[2] = luaControls->jump ? 1 : 0; - mov.mRotation[0] = mov.mRotation[1] = 0; - mov.mRotation[2] = luaControls->turn; - mov.mSpeedFactor = osg::Vec2(luaControls->movement, luaControls->sideMovement).length(); - - CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); - stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->run); - } - } if (aiActive && inProcessingRange) { if (engageCombatTimerStatus == Misc::TimerStatus::Elapsed) @@ -2082,7 +2065,7 @@ namespace MWMechanics if (iter->first != player) { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); - if (isConscious(iter->first) && !controlledFromLua) + if (isConscious(iter->first) && !(luaControls && luaControls->disableAI)) { stats.getAiSequence().execute(iter->first, *ctrl, duration); updateGreetingState(iter->first, *iter->second, timerUpdateHello > 0); @@ -2091,7 +2074,7 @@ namespace MWMechanics } } } - else if (aiActive && iter->first != player && isConscious(iter->first) && !controlledFromLua) + else if (aiActive && iter->first != player && isConscious(iter->first) && !(luaControls && luaControls->disableAI)) { CreatureStats &stats = iter->first.getClass().getCreatureStats(iter->first); stats.getAiSequence().execute(iter->first, *ctrl, duration, /*outOfRange*/true); @@ -2108,6 +2091,32 @@ namespace MWMechanics if (timerUpdateEquippedLight == 0) updateEquippedLight(iter->first, updateEquippedLightInterval, showTorches); } + + if (luaControls && isConscious(iter->first)) + { + Movement& mov = iter->first.getClass().getMovementSettings(iter->first); + CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); + float speedFactor = isPlayer ? 1.f : mov.mSpeedFactor; + osg::Vec2f movement = osg::Vec2f(mov.mPosition[0], mov.mPosition[1]) * speedFactor; + float rotationZ = mov.mRotation[2]; + bool jump = mov.mPosition[2] == 1; + bool runFlag = stats.getMovementFlag(MWMechanics::CreatureStats::Flag_Run); + if (luaControls->controlledFromLua) + { + mov.mPosition[0] = luaControls->sideMovement; + mov.mPosition[1] = luaControls->movement; + mov.mPosition[2] = luaControls->jump ? 1 : 0; + mov.mRotation[1] = 0; + mov.mRotation[2] = luaControls->turn; + mov.mSpeedFactor = osg::Vec2(luaControls->movement, luaControls->sideMovement).length(); + stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->run); + } + luaControls->sideMovement = movement.x(); + luaControls->movement = movement.y(); + luaControls->turn = rotationZ; + luaControls->jump = jump; + luaControls->run = runFlag; + } } }