1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-22 22:41:36 +00:00

Implement Yaw, Pitch and Use (attack / cast spell) in Lua self.controls

This commit is contained in:
uramer 2022-02-01 18:47:20 +00:00 committed by Petr Mikheev
parent 93b3b9df90
commit c31dedb89c
14 changed files with 50 additions and 45 deletions

View file

@ -56,7 +56,9 @@ namespace MWBase
bool mRun = false; bool mRun = false;
float mMovement = 0; float mMovement = 0;
float mSideMovement = 0; float mSideMovement = 0;
float mTurn = 0; float mPitchChange = 0;
float mYawChange = 0;
int mUse = 0;
}; };
virtual ActorControls* getActorControls(const MWWorld::Ptr&) const = 0; virtual ActorControls* getActorControls(const MWWorld::Ptr&) const = 0;

View file

@ -27,9 +27,11 @@ namespace MWLua
[](ActorControls& c, const TYPE& v) { c.FIELD = v; c.mChanged = true; }) [](ActorControls& c, const TYPE& v) { c.FIELD = v; c.mChanged = true; })
controls["movement"] = CONTROL(float, mMovement); controls["movement"] = CONTROL(float, mMovement);
controls["sideMovement"] = CONTROL(float, mSideMovement); 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["run"] = CONTROL(bool, mRun);
controls["jump"] = CONTROL(bool, mJump); controls["jump"] = CONTROL(bool, mJump);
controls["use"] = CONTROL(int, mUse);
#undef CONTROL #undef CONTROL
sol::usertype<SelfObject> selfAPI = sol::usertype<SelfObject> selfAPI =

View file

@ -49,7 +49,7 @@ namespace MWLua
{ {
auto* lua = context.mLua; auto* lua = context.mLua;
sol::table api(lua->sol(), sol::create); sol::table api(lua->sol(), sol::create);
api["API_REVISION"] = 14; api["API_REVISION"] = 15;
api["quit"] = [lua]() api["quit"] = [lua]()
{ {
Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback(); Log(Debug::Warning) << "Quit requested by a Lua script.\n" << lua->debugTraceback();

View file

@ -1401,9 +1401,6 @@ namespace MWMechanics
// AI processing is only done within given distance to the player. // AI processing is only done within given distance to the player.
bool inProcessingRange = distSqr <= mActorsProcessingRange*mActorsProcessingRange; 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 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() if (iter->first != player && (iter->first.getClass().getCreatureStats(iter->first).isDead()
|| !iter->first.getClass().getCreatureStats(iter->first).getAiSequence().isInCombat() || !iter->first.getClass().getCreatureStats(iter->first).getAiSequence().isInCombat()
@ -1524,25 +1521,31 @@ namespace MWMechanics
CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first); CreatureStats& stats = iter->first.getClass().getCreatureStats(iter->first);
float speedFactor = isPlayer ? 1.f : mov.mSpeedFactor; float speedFactor = isPlayer ? 1.f : mov.mSpeedFactor;
osg::Vec2f movement = osg::Vec2f(mov.mPosition[0], mov.mPosition[1]) * speedFactor; osg::Vec2f movement = osg::Vec2f(mov.mPosition[0], mov.mPosition[1]) * speedFactor;
float rotationX = mov.mRotation[0];
float rotationZ = mov.mRotation[2]; float rotationZ = mov.mRotation[2];
bool jump = mov.mPosition[2] == 1; bool jump = mov.mPosition[2] == 1;
bool runFlag = stats.getMovementFlag(MWMechanics::CreatureStats::Flag_Run); bool runFlag = stats.getMovementFlag(MWMechanics::CreatureStats::Flag_Run);
bool attackingOrSpell = stats.getAttackingOrSpell();
if (luaControls->mChanged) if (luaControls->mChanged)
{ {
mov.mPosition[0] = luaControls->mSideMovement; mov.mPosition[0] = luaControls->mSideMovement;
mov.mPosition[1] = luaControls->mMovement; mov.mPosition[1] = luaControls->mMovement;
mov.mPosition[2] = luaControls->mJump ? 1 : 0; mov.mPosition[2] = luaControls->mJump ? 1 : 0;
mov.mRotation[0] = luaControls->mPitchChange;
mov.mRotation[1] = 0; mov.mRotation[1] = 0;
mov.mRotation[2] = luaControls->mTurn; mov.mRotation[2] = luaControls->mYawChange;
mov.mSpeedFactor = osg::Vec2(luaControls->mMovement, luaControls->mSideMovement).length(); mov.mSpeedFactor = osg::Vec2(luaControls->mMovement, luaControls->mSideMovement).length();
stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->mRun); stats.setMovementFlag(MWMechanics::CreatureStats::Flag_Run, luaControls->mRun);
stats.setAttackingOrSpell(luaControls->mUse == 1);
luaControls->mChanged = false; luaControls->mChanged = false;
} }
luaControls->mSideMovement = movement.x(); luaControls->mSideMovement = movement.x();
luaControls->mMovement = movement.y(); luaControls->mMovement = movement.y();
luaControls->mTurn = rotationZ; luaControls->mPitchChange = rotationX;
luaControls->mYawChange = rotationZ;
luaControls->mJump = jump; luaControls->mJump = jump;
luaControls->mRun = runFlag; luaControls->mRun = runFlag;
luaControls->mUse = attackingOrSpell ? luaControls->mUse | 1 : luaControls->mUse & ~1;
} }
} }
} }

View file

@ -141,7 +141,7 @@ namespace MWMechanics
if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage); if (storage.mReadyToAttack) updateActorsMovement(actor, duration, storage);
if (storage.mRotateMove) if (storage.mRotateMove)
return false; return false;
storage.updateAttack(characterController); storage.updateAttack(actor, characterController);
} }
else else
{ {
@ -168,7 +168,7 @@ namespace MWMechanics
if (!canFight(actor, target)) if (!canFight(actor, target))
{ {
storage.stopAttack(); storage.stopAttack();
characterController.setAttackingOrSpell(false); actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false);
storage.mActionCooldown = 0.f; storage.mActionCooldown = 0.f;
// Continue combat if target is player or player follower/escorter and an attack has been attempted // Continue combat if target is player or player follower/escorter and an attack has been attempted
const std::list<MWWorld::Ptr>& playerFollowersAndEscorters = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(MWMechanics::getPlayer()); const std::list<MWWorld::Ptr>& playerFollowersAndEscorters = MWBase::Environment::get().getMechanicsManager()->getActorsSidingWith(MWMechanics::getPlayer());
@ -299,7 +299,7 @@ namespace MWMechanics
{ {
storage.mUseCustomDestination = false; storage.mUseCustomDestination = false;
storage.stopAttack(); storage.stopAttack();
characterController.setAttackingOrSpell(false); actor.getClass().getCreatureStats(actor).setAttackingOrSpell(false);
currentAction.reset(new ActionFlee()); currentAction.reset(new ActionFlee());
actionCooldown = currentAction->getActionCooldown(); actionCooldown = currentAction->getActionCooldown();
storage.startFleeing(); storage.startFleeing();
@ -575,7 +575,7 @@ namespace MWMechanics
if (mAttackCooldown <= 0) if (mAttackCooldown <= 0)
{ {
mAttack = true; // attack starts just now mAttack = true; // attack starts just now
characterController.setAttackingOrSpell(true); actor.getClass().getCreatureStats(actor).setAttackingOrSpell(true);
if (!distantCombat) if (!distantCombat)
characterController.setAIAttackType(chooseBestAttack(weapon)); 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())) if (mAttack && (characterController.getAttackStrength() >= mStrength || characterController.readyToPrepareAttack()))
{ {
mAttack = false; mAttack = false;
} }
characterController.setAttackingOrSpell(mAttack); actor.getClass().getCreatureStats(actor).setAttackingOrSpell(mAttack);
} }
void AiCombatStorage::stopAttack() void AiCombatStorage::stopAttack()

View file

@ -88,7 +88,7 @@ namespace MWMechanics
void stopCombatMove(); void stopCombatMove();
void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController, void startAttackIfReady(const MWWorld::Ptr& actor, CharacterController& characterController,
const ESM::Weapon* weapon, bool distantCombat); const ESM::Weapon* weapon, bool distantCombat);
void updateAttack(CharacterController& characterController); void updateAttack(const MWWorld::Ptr& actor, CharacterController& characterController);
void stopAttack(); void stopAttack();
void startFleeing(); void startFleeing();

View file

@ -854,7 +854,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim
, mSecondsOfSwimming(0) , mSecondsOfSwimming(0)
, mSecondsOfRunning(0) , mSecondsOfRunning(0)
, mTurnAnimationThreshold(0) , mTurnAnimationThreshold(0)
, mAttackingOrSpell(false)
, mCastingManualSpell(false) , mCastingManualSpell(false)
, mTimeUntilWake(0.f) , mTimeUntilWake(0.f)
, mIsMovingBackward(false) , mIsMovingBackward(false)
@ -1138,7 +1137,7 @@ bool CharacterController::updateCreatureState()
mAnimation->disable(mCurrentWeapon); mAnimation->disable(mCurrentWeapon);
} }
if(mAttackingOrSpell) if(getAttackingOrSpell())
{ {
if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None) if(mUpperBodyState == UpperCharState_Nothing && mHitState == CharState_None)
{ {
@ -1202,7 +1201,7 @@ bool CharacterController::updateCreatureState()
} }
} }
mAttackingOrSpell = false; setAttackingOrSpell(false);
} }
bool animPlaying = mAnimation->getInfo(mCurrentWeapon); bool animPlaying = mAnimation->getInfo(mCurrentWeapon);
@ -1277,11 +1276,10 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
{ {
forcestateupdate = true; forcestateupdate = true;
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
mAttackingOrSpell = false; setAttackingOrSpell(false);
mAnimation->disable(mCurrentWeapon); mAnimation->disable(mCurrentWeapon);
mAnimation->showWeapons(true); mAnimation->showWeapons(true);
if (mPtr == getPlayer()) stats.setAttackingOrSpell(false);
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
} }
if(!isKnockedOut() && !isKnockedDown() && !isRecovery()) if(!isKnockedOut() && !isKnockedDown() && !isRecovery())
@ -1456,7 +1454,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
float complete; float complete;
bool animPlaying; bool animPlaying;
ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass; ESM::WeaponType::Class weapclass = getWeaponType(mWeaponType)->mWeaponClass;
if(mAttackingOrSpell) if(getAttackingOrSpell())
{ {
MWWorld::Ptr player = getPlayer(); MWWorld::Ptr player = getPlayer();
@ -1478,11 +1476,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
{ {
// Unset casting flag, otherwise pressing the mouse button down would // Unset casting flag, otherwise pressing the mouse button down would
// continue casting every frame if there is no animation // continue casting every frame if there is no animation
mAttackingOrSpell = false; setAttackingOrSpell(false);
if (mPtr == player) if (mPtr == player)
{ {
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false);
// For the player, set the spell we want to cast // For the player, set the spell we want to cast
// This has to be done at the start of the casting animation, // 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) // *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. // 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 minAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"min attack");
float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack"); float maxAttackTime = mAnimation->getTextKeyTime(mCurrentWeapon+": "+mAttackType+" "+"max attack");
if (mAttackingOrSpell || minAttackTime == maxAttackTime) if (getAttackingOrSpell() || minAttackTime == maxAttackTime)
{ {
start = mAttackType+" min attack"; start = mAttackType+" min attack";
stop = mAttackType+" max attack"; stop = mAttackType+" max attack";
@ -2647,7 +2643,7 @@ void CharacterController::forceStateUpdate()
// Make sure we canceled the current attack or spellcasting, // Make sure we canceled the current attack or spellcasting,
// because we disabled attack animations anyway. // because we disabled attack animations anyway.
mCastingManualSpell = false; mCastingManualSpell = false;
mAttackingOrSpell = false; setAttackingOrSpell(false);
if (mUpperBodyState != UpperCharState_Nothing) if (mUpperBodyState != UpperCharState_Nothing)
mUpperBodyState = UpperCharState_WeapEquiped; mUpperBodyState = UpperCharState_WeapEquiped;
@ -2845,12 +2841,12 @@ bool CharacterController::isRunning() const
void CharacterController::setAttackingOrSpell(bool attackingOrSpell) void CharacterController::setAttackingOrSpell(bool attackingOrSpell)
{ {
mAttackingOrSpell = attackingOrSpell; mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(attackingOrSpell);
} }
void CharacterController::castSpell(const std::string& spellId, bool manualSpell) void CharacterController::castSpell(const std::string& spellId, bool manualSpell)
{ {
mAttackingOrSpell = true; setAttackingOrSpell(true);
mCastingManualSpell = manualSpell; mCastingManualSpell = manualSpell;
ActionSpell action = ActionSpell(spellId); ActionSpell action = ActionSpell(spellId);
action.prepare(mPtr); action.prepare(mPtr);
@ -2894,6 +2890,11 @@ float CharacterController::getAttackStrength() const
return mAttackStrength; return mAttackStrength;
} }
bool CharacterController::getAttackingOrSpell()
{
return mPtr.getClass().getCreatureStats(mPtr).getAttackingOrSpell();
}
void CharacterController::setActive(int active) void CharacterController::setActive(int active)
{ {
mAnimation->setActive(active); mAnimation->setActive(active);

View file

@ -188,7 +188,6 @@ class CharacterController : public MWRender::Animation::TextKeyListener
std::string mAttackType; // slash, chop or thrust std::string mAttackType; // slash, chop or thrust
bool mAttackingOrSpell;
bool mCastingManualSpell; bool mCastingManualSpell;
float mTimeUntilWake; float mTimeUntilWake;
@ -235,6 +234,10 @@ class CharacterController : public MWRender::Animation::TextKeyListener
std::string getWeaponAnimation(int weaponType) const; std::string getWeaponAnimation(int weaponType) const;
bool getAttackingOrSpell();
void setAttackingOrSpell(bool attackingOrSpell);
public: public:
CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim);
virtual ~CharacterController(); virtual ~CharacterController();
@ -285,7 +288,6 @@ public:
bool isAttackingOrSpell() const; bool isAttackingOrSpell() const;
void setVisibility(float visibility); void setVisibility(float visibility);
void setAttackingOrSpell(bool attackingOrSpell);
void castSpell(const std::string& spellId, bool manualSpell=false); void castSpell(const std::string& spellId, bool manualSpell=false);
void setAIAttackType(const std::string& attackType); void setAIAttackType(const std::string& attackType);
static void setAttackTypeRandomly(std::string& attackType); static void setAttackTypeRandomly(std::string& attackType);

View file

@ -24,6 +24,7 @@ namespace MWMechanics
mHitRecovery(false), mBlock(false), mMovementFlags(0), mHitRecovery(false), mBlock(false), mMovementFlags(0),
mFallHeight(0), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1), mFallHeight(0), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1),
mDeathAnimation(-1), mTimeOfDeath(), mSideMovementAngle(0), mLevel (0) mDeathAnimation(-1), mTimeOfDeath(), mSideMovementAngle(0), mLevel (0)
, mAttackingOrSpell(false)
{ {
for (int i=0; i<4; ++i) for (int i=0; i<4; ++i)
mAiSettings[i] = 0; mAiSettings[i] = 0;

View file

@ -92,6 +92,7 @@ namespace MWMechanics
protected: protected:
int mLevel; int mLevel;
bool mAttackingOrSpell;
public: public:
CreatureStats(); CreatureStats();
@ -124,7 +125,7 @@ namespace MWMechanics
const MagicEffects & getMagicEffects() const; const MagicEffects & getMagicEffects() const;
bool getAttackingOrSpell() const; bool getAttackingOrSpell() const { return mAttackingOrSpell; }
int getLevel() const; int getLevel() const;
@ -149,7 +150,7 @@ namespace MWMechanics
/// Set Modifier for each magic effect according to \a effects. Does not touch Base values. /// Set Modifier for each magic effect according to \a effects. Does not touch Base values.
void modifyMagicEffects(const MagicEffects &effects); void modifyMagicEffects(const MagicEffects &effects);
void setAttackingOrSpell(bool attackingOrSpell); void setAttackingOrSpell(bool attackingOrSpell) { mAttackingOrSpell = attackingOrSpell; }
void setLevel(int level); void setLevel(int level);

View file

@ -957,7 +957,7 @@ void NpcAnimation::showWeapons(bool showWeapon)
removeIndividualPart(ESM::PRT_Weapon); removeIndividualPart(ESM::PRT_Weapon);
// If we remove/hide weapon from player, we should reset attack animation as well // If we remove/hide weapon from player, we should reset attack animation as well
if (mPtr == MWMechanics::getPlayer()) if (mPtr == MWMechanics::getPlayer())
MWBase::Environment::get().getWorld()->getPlayer().setAttackingOrSpell(false); mPtr.getClass().getCreatureStats(mPtr).setAttackingOrSpell(false);
} }
updateHolsteredWeapon(!mShowWeapons); updateHolsteredWeapon(!mShowWeapons);

View file

@ -39,7 +39,6 @@ namespace MWWorld
mTeleported(false), mTeleported(false),
mCurrentCrimeId(-1), mCurrentCrimeId(-1),
mPaidCrimeId(-1), mPaidCrimeId(-1),
mAttackingOrSpell(false),
mJumping(false) mJumping(false)
{ {
ESM::CellRef cellRef; ESM::CellRef cellRef;
@ -266,12 +265,7 @@ namespace MWWorld
void Player::setAttackingOrSpell(bool attackingOrSpell) void Player::setAttackingOrSpell(bool attackingOrSpell)
{ {
mAttackingOrSpell = attackingOrSpell; getPlayer().getClass().getCreatureStats(getPlayer()).setAttackingOrSpell(attackingOrSpell);
}
bool Player::getAttackingOrSpell() const
{
return mAttackingOrSpell;
} }
void Player::setJumping(bool jumping) void Player::setJumping(bool jumping)
@ -314,7 +308,6 @@ namespace MWWorld
mAutoMove = false; mAutoMove = false;
mForwardBackward = 0; mForwardBackward = 0;
mTeleported = false; mTeleported = false;
mAttackingOrSpell = false;
mJumping = false; mJumping = false;
mCurrentCrimeId = -1; mCurrentCrimeId = -1;
mPaidCrimeId = -1; mPaidCrimeId = -1;

View file

@ -56,7 +56,6 @@ namespace MWWorld
float mSaveSkills[ESM::Skill::Length]; float mSaveSkills[ESM::Skill::Length];
float mSaveAttributes[ESM::Attribute::Length]; float mSaveAttributes[ESM::Attribute::Length];
bool mAttackingOrSpell;
bool mJumping; bool mJumping;
public: public:
@ -112,7 +111,6 @@ namespace MWWorld
void setTeleported(bool teleported); void setTeleported(bool teleported);
void setAttackingOrSpell(bool attackingOrSpell); void setAttackingOrSpell(bool attackingOrSpell);
bool getAttackingOrSpell() const;
void setJumping(bool jumping); void setJumping(bool jumping);
bool getJumping() const; bool getJumping() const;

View file

@ -30,9 +30,11 @@
-- @type ActorControls -- @type ActorControls
-- @field [parent=#ActorControls] #number movement +1 - move forward, -1 - move backward -- @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 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 run true - run, false - walk
-- @field [parent=#ActorControls] #boolean jump If true - initiate a jump -- @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). -- Enables or disables standart AI (enabled by default).