diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e56a4eb8a..43a645ed14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 49) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 62) +set(OPENMW_LUA_API_REVISION 63) set(OPENMW_POSTPROCESSING_API_REVISION 1) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 3b0d44a984..4e7b171ff0 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -1,6 +1,7 @@ #include "localscripts.hpp" #include +#include #include #include "../mwbase/environment.hpp" @@ -13,6 +14,7 @@ #include "../mwmechanics/aisequence.hpp" #include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/aiwander.hpp" +#include "../mwmechanics/attacktype.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" @@ -63,6 +65,11 @@ namespace MWLua selfAPI["controls"] = sol::readonly_property([](SelfObject& self) { return &self.mControls; }); selfAPI["isActive"] = [](SelfObject& self) { return &self.mIsActive; }; selfAPI["enableAI"] = [](SelfObject& self, bool v) { self.mControls.mDisableAI = !v; }; + selfAPI["ATTACK_TYPE"] + = LuaUtil::makeStrictReadOnly(context.mLua->tableFromPairs( + { { "NoAttack", MWMechanics::AttackType::NoAttack }, { "Any", MWMechanics::AttackType::Any }, + { "Chop", MWMechanics::AttackType::Chop }, { "Slash", MWMechanics::AttackType::Slash }, + { "Thrust", MWMechanics::AttackType::Thrust } })); using AiPackage = MWMechanics::AiPackage; sol::usertype aiPackage = context.mLua->sol().new_usertype("AiPackage"); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 525044d55c..191ad86733 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -47,6 +47,7 @@ #include "aifollow.hpp" #include "aipursue.hpp" #include "aiwander.hpp" +#include "attacktype.hpp" #include "character.hpp" #include "creaturestats.hpp" #include "movement.hpp" @@ -239,6 +240,23 @@ namespace MWMechanics namespace { + std::string_view attackTypeName(AttackType attackType) + { + switch (attackType) + { + case AttackType::NoAttack: + case AttackType::Any: + return {}; + case AttackType::Chop: + return "chop"; + case AttackType::Slash: + return "slash"; + case AttackType::Thrust: + return "thrust"; + } + throw std::logic_error("Invalid attack type value: " + std::to_string(static_cast(attackType))); + } + float getTimeToDestination(const AiPackage& package, const osg::Vec3f& position, float speed, float duration, const osg::Vec3f& halfExtents) { @@ -363,7 +381,11 @@ namespace MWMechanics mov.mSpeedFactor = osg::Vec2(controls.mMovement, controls.mSideMovement).length(); stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, controls.mRun); stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Sneak, controls.mSneak); - stats.setAttackingOrSpell((controls.mUse & 1) == 1); + + AttackType attackType = static_cast(controls.mUse); + stats.setAttackingOrSpell(attackType != AttackType::NoAttack); + stats.setAttackType(attackTypeName(attackType)); + controls.mChanged = false; } // For the player we don't need to copy these values to Lua because mwinput doesn't change them. diff --git a/apps/openmw/mwmechanics/attacktype.hpp b/apps/openmw/mwmechanics/attacktype.hpp new file mode 100644 index 0000000000..3824f5bbe7 --- /dev/null +++ b/apps/openmw/mwmechanics/attacktype.hpp @@ -0,0 +1,16 @@ +#ifndef OPENMW_MWMECHANICS_ATTACKTYPE_H +#define OPENMW_MWMECHANICS_ATTACKTYPE_H + +namespace MWMechanics +{ + enum class AttackType + { + NoAttack, + Any, + Chop, + Slash, + Thrust + }; +} + +#endif diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 27c3cff6b8..dbd00cd7ff 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1674,7 +1674,12 @@ namespace MWMechanics } } else if (aiInactive) - mAttackType = getRandomAttackType(); + { + mAttackType = getDesiredAttackType(); + if (mAttackType == "") + mAttackType = getRandomAttackType(); + } + // else if (mPtr != getPlayer()) use mAttackType set by AiCombat startKey = mAttackType + ' ' + startKey; stopKey = mAttackType + " max attack"; @@ -3003,6 +3008,11 @@ namespace MWMechanics return mPtr.getClass().getCreatureStats(mPtr).getAttackingOrSpell(); } + std::string_view CharacterController::getDesiredAttackType() const + { + return mPtr.getClass().getCreatureStats(mPtr).getAttackType(); + } + void CharacterController::setActive(int active) const { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 8ead23f659..f043419a81 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -247,6 +247,8 @@ namespace MWMechanics bool getAttackingOrSpell() const; void setAttackingOrSpell(bool attackingOrSpell) const; + std::string_view getDesiredAttackType() const; + void prepareHit(); public: diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 7989357634..3f7c57094c 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -97,6 +97,7 @@ namespace MWMechanics protected: int mLevel; bool mAttackingOrSpell; + std::string mAttackType; public: CreatureStats(); @@ -130,6 +131,7 @@ namespace MWMechanics const MagicEffects& getMagicEffects() const; bool getAttackingOrSpell() const { return mAttackingOrSpell; } + std::string_view getAttackType() const { return mAttackType; } int getLevel() const; @@ -156,6 +158,8 @@ namespace MWMechanics void setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; } + void setAttackType(std::string_view attackType) { mAttackType = attackType; } + void setLevel(int level); void setAiSetting(AiSetting index, Stat value); diff --git a/files/lua_api/openmw/self.lua b/files/lua_api/openmw/self.lua index 6123c36ae6..1af7fe99a3 100644 --- a/files/lua_api/openmw/self.lua +++ b/files/lua_api/openmw/self.lua @@ -37,7 +37,15 @@ -- @field [parent=#ActorControls] #boolean run true - run, false - walk -- @field [parent=#ActorControls] #boolean sneak If true - sneak -- @field [parent=#ActorControls] #boolean jump If true - initiate a jump --- @field [parent=#ActorControls] #number use if 1 - activates the readied weapon/spell. For weapons, keeping at 1 will charge the attack until set to 0. +-- @field [parent=#ActorControls] #ATTACK_TYPE use Activates the readied weapon/spell according to a provided value. For weapons, keeping this value modified will charge the attack until set to @{#ATTACK_TYPE.NoAttack}. If an @{#ATTACK_TYPE} not appropriate for a currently equipped weapon provided - an appropriate @{#ATTACK_TYPE} will be used instead. + +--- +-- @type ATTACK_TYPE +-- @field #number NoAttack +-- @field #number Any +-- @field #number Chop +-- @field #number Swing +-- @field #number Thrust --- -- Enables or disables standard AI (enabled by default).