From c31dedb89cd9391b4700f6f1a7f26eee724a7969 Mon Sep 17 00:00:00 2001 From: uramer Date: Tue, 1 Feb 2022 18:47:20 +0000 Subject: [PATCH] Implement Yaw, Pitch and Use (attack / cast spell) in Lua self.controls --- apps/openmw/mwbase/luamanager.hpp | 4 +++- apps/openmw/mwlua/localscripts.cpp | 4 +++- apps/openmw/mwlua/luabindings.cpp | 2 +- apps/openmw/mwmechanics/actors.cpp | 13 ++++++---- apps/openmw/mwmechanics/aicombat.cpp | 12 +++++----- apps/openmw/mwmechanics/aicombat.hpp | 2 +- apps/openmw/mwmechanics/character.cpp | 29 ++++++++++++----------- apps/openmw/mwmechanics/character.hpp | 6 +++-- apps/openmw/mwmechanics/creaturestats.cpp | 1 + apps/openmw/mwmechanics/creaturestats.hpp | 5 ++-- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwworld/player.cpp | 9 +------ apps/openmw/mwworld/player.hpp | 2 -- files/lua_api/openmw/self.lua | 4 +++- 14 files changed, 50 insertions(+), 45 deletions(-) diff --git a/apps/openmw/mwbase/luamanager.hpp b/apps/openmw/mwbase/luamanager.hpp index cc479a2937..8c0c5d61de 100644 --- a/apps/openmw/mwbase/luamanager.hpp +++ b/apps/openmw/mwbase/luamanager.hpp @@ -56,7 +56,9 @@ namespace MWBase bool mRun = false; float mMovement = 0; float mSideMovement = 0; - float mTurn = 0; + float mPitchChange = 0; + float mYawChange = 0; + int mUse = 0; }; virtual ActorControls* getActorControls(const MWWorld::Ptr&) const = 0; diff --git a/apps/openmw/mwlua/localscripts.cpp b/apps/openmw/mwlua/localscripts.cpp index 98cf0a0b1a..918970dc54 100644 --- a/apps/openmw/mwlua/localscripts.cpp +++ b/apps/openmw/mwlua/localscripts.cpp @@ -27,9 +27,11 @@ namespace MWLua [](ActorControls& c, const TYPE& v) { c.FIELD = v; c.mChanged = true; }) controls["movement"] = CONTROL(float, mMovement); controls["sideMovement"] = CONTROL(float, mSideMovement); - controls["turn"] = CONTROL(float, mTurn); + 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 sol::usertype selfAPI = diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index cf60e00728..309ab51c08 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -49,7 +49,7 @@ namespace MWLua { auto* lua = context.mLua; sol::table api(lua->sol(), sol::create); - api["API_REVISION"] = 14; + api["API_REVISION"] = 15; api["quit"] = [lua]() { Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 7c94c4e604..c567ea464c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1401,9 +1401,6 @@ namespace MWMechanics // AI processing is only done within given distance to the player. bool inProcessingRange = distSqr <= mActorsProcessingRange*mActorsProcessingRange; - if (isPlayer) - ctrl->setAttackingOrSpell(world->getPlayer().getAttackingOrSpell()); - // If dead or no longer in combat, no longer store any actors who attempted to hit us. Also remove for the player. if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead() || !iter->first.getClass().getCreatureStats(iter->first).getAiSequence().isInCombat() @@ -1524,25 +1521,31 @@ namespace MWMechanics 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 rotationX = mov.mRotation[0]; float rotationZ = mov.mRotation[2]; bool jump = mov.mPosition[2] == 1; bool runFlag = stats.getMovementFlag(MWMechanics::CreatureStats::Flag_Run); + bool attackingOrSpell = stats.getAttackingOrSpell(); if (luaControls->mChanged) { mov.mPosition[0] = luaControls->mSideMovement; mov.mPosition[1] = luaControls->mMovement; mov.mPosition[2] = luaControls->mJump ? 1 : 0; + mov.mRotation[0] = luaControls->mPitchChange; mov.mRotation[1] = 0; - mov.mRotation[2] = luaControls->mTurn; + mov.mRotation[2] = luaControls->mYawChange; mov.mSpeedFactor = osg::Vec2(luaControls->mMovement, luaControls->mSideMovement).length(); stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->mRun); + stats.setAttackingOrSpell(luaControls->mUse == 1); luaControls->mChanged = false; } luaControls->mSideMovement = movement.x(); luaControls->mMovement = movement.y(); - luaControls->mTurn = rotationZ; + luaControls->mPitchChange = rotationX; + luaControls->mYawChange = rotationZ; luaControls->mJump = jump; luaControls->mRun = runFlag; + luaControls->mUse = attackingOrSpell ? luaControls->mUse | 1 : luaControls->mUse & ~1; } } } diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 46f04b6f97..83ff795545 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -141,7 +141,7 @@ namespace MWMechanics if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage); if (storage.mRotateMove) return false; - storage.updateAttack(characterController); + storage.updateAttack(actor, characterController); } else { @@ -168,7 +168,7 @@ namespace MWMechanics if (!canFight(actor, target)) { storage.stopAttack(); - characterController.setAttackingOrSpell(false); + actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false); storage.mActionCooldown = 0.f; // Continue combat if target is player or player follower/escorter and an attack has been attempted const std::list& playerFollowersAndEscorters = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(MWMechanics::getPlayer()); @@ -299,7 +299,7 @@ namespace MWMechanics { storage.mUseCustomDestination = false; storage.stopAttack(); - characterController.setAttackingOrSpell(false); + actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false); currentAction.reset(new ActionFlee()); actionCooldown = currentAction->getActionCooldown(); storage.startFleeing(); @@ -575,7 +575,7 @@ namespace MWMechanics if (mAttackCooldown <= 0) { mAttack = true; // attack starts just now - characterController.setAttackingOrSpell(true); + actor.getClass().getCreatureStats(actor).setAttackingOrSpell(true); if (!distantCombat) characterController.setAIAttackType(chooseBestAttack(weapon)); @@ -603,13 +603,13 @@ namespace MWMechanics } } - void AiCombatStorage::updateAttack(CharacterController& characterController) + void AiCombatStorage::updateAttack(const MWWorld::Ptr& actor, CharacterController& characterController) { if (mAttack && (characterController.getAttackStrength() >= mStrength || characterController.readyToPrepareAttack())) { mAttack = false; } - characterController.setAttackingOrSpell(mAttack); + actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mAttack); } void AiCombatStorage::stopAttack() diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index 34e726412c..c783994b97 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -88,7 +88,7 @@ namespace MWMechanics void stopCombatMove(); void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, const ESM::Weapon* weapon, bool distantCombat); - void updateAttack(CharacterController& characterController); + void updateAttack(const MWWorld::Ptr& actor, CharacterController& characterController); void stopAttack(); void startFleeing(); diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6c33f86c76..0f8e2ebd97 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -854,7 +854,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mSecondsOfSwimming(0) , mSecondsOfRunning(0) , mTurnAnimationThreshold(0) - , mAttackingOrSpell(false) , mCastingManualSpell(false) , mTimeUntilWake(0.f) , mIsMovingBackward(false) @@ -1138,7 +1137,7 @@ bool CharacterController::updateCreatureState() mAnimation->disable(mCurrentWeapon); } - if(mAttackingOrSpell) + if(getAttackingOrSpell()) { if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None) { @@ -1202,7 +1201,7 @@ bool CharacterController::updateCreatureState() } } - mAttackingOrSpell = false; + setAttackingOrSpell(false); } bool animPlaying = mAnimation->getInfo(mCurrentWeapon); @@ -1277,11 +1276,10 @@ bool CharacterController::updateWeaponState(CharacterState& idle) { forcestateupdate = true; mUpperBodyState = UpperCharState_WeapEquiped; - mAttackingOrSpell = false; + setAttackingOrSpell(false); mAnimation->disable(mCurrentWeapon); mAnimation->showWeapons(true); - if (mPtr == getPlayer()) - MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); + stats.setAttackingOrSpell(false); } if(!isKnockedOut() && !isKnockedDown() && !isRecovery()) @@ -1456,7 +1454,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) float complete; bool animPlaying; ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass; - if(mAttackingOrSpell) + if(getAttackingOrSpell()) { MWWorld::Ptr player = getPlayer(); @@ -1478,11 +1476,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle) { // Unset casting flag, otherwise pressing the mouse button down would // continue casting every frame if there is no animation - mAttackingOrSpell = false; + setAttackingOrSpell(false); if (mPtr == player) { - MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); - // For the player, set the spell we want to cast // This has to be done at the start of the casting animation, // *not* when selecting a spell in the GUI (otherwise you could change the spell mid-animation) @@ -1791,7 +1787,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle) // Note: if the "min attack"->"max attack" is a stub, "play" it anyway. Attack strength will be random. float minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack"); float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack"); - if (mAttackingOrSpell || minAttackTime == maxAttackTime) + if (getAttackingOrSpell() || minAttackTime == maxAttackTime) { start = mAttackType+" min attack"; stop = mAttackType+" max attack"; @@ -2647,7 +2643,7 @@ void CharacterController::forceStateUpdate() // Make sure we canceled the current attack or spellcasting, // because we disabled attack animations anyway. mCastingManualSpell = false; - mAttackingOrSpell = false; + setAttackingOrSpell(false); if (mUpperBodyState != UpperCharState_Nothing) mUpperBodyState = UpperCharState_WeapEquiped; @@ -2845,12 +2841,12 @@ bool CharacterController::isRunning() const void CharacterController::setAttackingOrSpell(bool attackingOrSpell) { - mAttackingOrSpell = attackingOrSpell; + mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(attackingOrSpell); } void CharacterController::castSpell(const std::string& spellId, bool manualSpell) { - mAttackingOrSpell = true; + setAttackingOrSpell(true); mCastingManualSpell = manualSpell; ActionSpell action = ActionSpell(spellId); action.prepare(mPtr); @@ -2894,6 +2890,11 @@ float CharacterController::getAttackStrength() const return mAttackStrength; } +bool CharacterController::getAttackingOrSpell() +{ + return mPtr.getClass().getCreatureStats(mPtr).getAttackingOrSpell(); +} + void CharacterController::setActive(int active) { mAnimation->setActive(active); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index adeaa739af..1647980541 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -188,7 +188,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener std::string mAttackType; // slash, chop or thrust - bool mAttackingOrSpell; bool mCastingManualSpell; float mTimeUntilWake; @@ -235,6 +234,10 @@ class CharacterController : public MWRender::Animation::TextKeyListener std::string getWeaponAnimation(int weaponType) const; + bool getAttackingOrSpell(); + void setAttackingOrSpell(bool attackingOrSpell); + + public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); @@ -285,7 +288,6 @@ public: bool isAttackingOrSpell() const; void setVisibility(float visibility); - void setAttackingOrSpell(bool attackingOrSpell); void castSpell(const std::string& spellId, bool manualSpell=false); void setAIAttackType(const std::string& attackType); static void setAttackTypeRandomly(std::string& attackType); diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 03c2d3f41f..9611f5b34a 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -24,6 +24,7 @@ namespace MWMechanics mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1), mDeathAnimation(-1), mTimeOfDeath(), mSideMovementAngle(0), mLevel (0) + , mAttackingOrSpell(false) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 002991e004..2bcb452292 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -92,6 +92,7 @@ namespace MWMechanics protected: int mLevel; + bool mAttackingOrSpell; public: CreatureStats(); @@ -124,7 +125,7 @@ namespace MWMechanics const MagicEffects & getMagicEffects() const; - bool getAttackingOrSpell() const; + bool getAttackingOrSpell() const { return mAttackingOrSpell; } int getLevel() const; @@ -149,7 +150,7 @@ namespace MWMechanics /// Set Modifier for each magic effect according to \a effects. Does not touch Base values. void modifyMagicEffects(const MagicEffects &effects); - void setAttackingOrSpell(bool attackingOrSpell); + void setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; } void setLevel(int level); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index da361aec25..308762045c 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -957,7 +957,7 @@ void NpcAnimation::showWeapons(bool showWeapon) removeIndividualPart(ESM::PRT_Weapon); // If we remove/hide weapon from player, we should reset attack animation as well if (mPtr == MWMechanics::getPlayer()) - MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); + mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(false); } updateHolsteredWeapon(!mShowWeapons); diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index 3902a409e5..7062366697 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -39,7 +39,6 @@ namespace MWWorld mTeleported(false), mCurrentCrimeId(-1), mPaidCrimeId(-1), - mAttackingOrSpell(false), mJumping(false) { ESM::CellRef cellRef; @@ -266,12 +265,7 @@ namespace MWWorld void Player::setAttackingOrSpell(bool attackingOrSpell) { - mAttackingOrSpell = attackingOrSpell; - } - - bool Player::getAttackingOrSpell() const - { - return mAttackingOrSpell; + getPlayer().getClass().getCreatureStats(getPlayer()).setAttackingOrSpell(attackingOrSpell); } void Player::setJumping(bool jumping) @@ -314,7 +308,6 @@ namespace MWWorld mAutoMove = false; mForwardBackward = 0; mTeleported = false; - mAttackingOrSpell = false; mJumping = false; mCurrentCrimeId = -1; mPaidCrimeId = -1; diff --git a/apps/openmw/mwworld/player.hpp b/apps/openmw/mwworld/player.hpp index 2770042969..4add58541e 100644 --- a/apps/openmw/mwworld/player.hpp +++ b/apps/openmw/mwworld/player.hpp @@ -56,7 +56,6 @@ namespace MWWorld float mSaveSkills[ESM::Skill::Length]; float mSaveAttributes[ESM::Attribute::Length]; - bool mAttackingOrSpell; bool mJumping; public: @@ -112,7 +111,6 @@ namespace MWWorld void setTeleported(bool teleported); void setAttackingOrSpell(bool attackingOrSpell); - bool getAttackingOrSpell() const; void setJumping(bool jumping); bool getJumping() const; diff --git a/files/lua_api/openmw/self.lua b/files/lua_api/openmw/self.lua index 98f1071cf6..1228a92a87 100644 --- a/files/lua_api/openmw/self.lua +++ b/files/lua_api/openmw/self.lua @@ -30,9 +30,11 @@ -- @type ActorControls -- @field [parent=#ActorControls] #number movement +1 - move forward, -1 - move backward -- @field [parent=#ActorControls] #number sideMovement +1 - move right, -1 - move left --- @field [parent=#ActorControls] #number turn Turn right (radians); if negative - turn left +-- @field [parent=#ActorControls] #number yawChange Turn right (radians); if negative - turn left +-- @field [parent=#ActorControls] #number pitchChange Look down (radians); if negative - look up -- @field [parent=#ActorControls] #boolean run true - run, false - walk -- @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. ------------------------------------------------------------------------------- -- Enables or disables standart AI (enabled by default).