From 8dd930cf97fc4a0fee398a31209fabf24ad7fcb1 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Fri, 13 Dec 2013 22:43:58 +0200 Subject: [PATCH 01/11] bug fix http://bugs.openmw.org/issues/428 --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwbase/world.hpp | 3 ++ apps/openmw/mwgui/mainmenu.cpp | 13 +++++++- apps/openmw/mwgui/mainmenu.hpp | 4 +++ apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++ apps/openmw/mwgui/windowmanagerimp.hpp | 3 ++ apps/openmw/mwinput/inputmanagerimp.cpp | 37 ++++++++++++----------- apps/openmw/mwmechanics/actors.cpp | 14 ++++----- apps/openmw/mwmechanics/character.cpp | 22 ++++++++++++-- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 +++ apps/openmw/mwrender/renderingmanager.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 9 +++++- apps/openmw/mwworld/worldimp.hpp | 2 ++ 14 files changed, 92 insertions(+), 31 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c47ad066b..4ffb44615 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -202,6 +202,8 @@ namespace MWBase virtual void setSpellVisibility(bool visible) = 0; virtual void setSneakVisibility(bool visible) = 0; + void virtual setMainMenuNoReturn(bool noreturn) = 0; + virtual void activateQuickKey (int index) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 8141af712..b1f236bd1 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -40,6 +40,7 @@ namespace ESM namespace MWRender { + class Camera; class ExternalRendering; class Animation; } @@ -115,6 +116,8 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; + virtual MWRender::Camera* getCamera() const = 0; + virtual const MWWorld::ESMStore& getStore() const = 0; virtual std::vector& getEsmReader() = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index fa7ed2ace..e1c72193b 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -17,6 +17,7 @@ namespace MWGui MainMenu::MainMenu(int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") , mButtonBox(0) + , mNoReturn(false) { onResChange(w,h); } @@ -33,7 +34,8 @@ namespace MWGui int curH = 0; std::vector buttons; - buttons.push_back("return"); + if(!mNoReturn) + buttons.push_back("return"); buttons.push_back("newgame"); //buttons.push_back("loadgame"); //buttons.push_back("savegame"); @@ -68,6 +70,15 @@ namespace MWGui mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH); } + void MainMenu::setNoReturn(bool bNoReturn) + { + if (mNoReturn != bNoReturn) + { + mNoReturn = bNoReturn; + onResChange( Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video") ); + } + } + void MainMenu::onButtonClicked(MyGUI::Widget *sender) { MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index 4e76a64df..a686cb020 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -12,9 +12,13 @@ namespace MWGui void onResChange(int w, int h); + void setNoReturn(bool bNoReturn); + private: MyGUI::Widget* mButtonBox; + bool mNoReturn; + std::map mButtons; void onButtonClicked (MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 78986a052..69ec11ccc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -880,6 +880,11 @@ namespace MWGui mHud->setSneakVisible(visible); } + void WindowManager::setMainMenuNoReturn(bool noreturn) + { + mMenu->setNoReturn(noreturn); + } + void WindowManager::setDragDrop(bool dragDrop) { mToolTips->setEnabled(!dragDrop); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4f1960295..3d6972718 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -198,6 +198,9 @@ namespace MWGui virtual void setSpellVisibility(bool visible); virtual void setSneakVisibility(bool visible); + //disables 'return' button in the main menu (used when player is dead) + void virtual setMainMenuNoReturn(bool noreturn); + virtual void activateQuickKey (int index); virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ab2569635..9b7fe98bd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -367,24 +367,27 @@ namespace MWInput } } - if (mControlSwitch["playerviewswitch"]) { - - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) - { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - } - } else { - if (mPreviewPOVDelay > 0.5) { - //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - } else if (mPreviewPOVDelay > 0.f) { - MWBase::Environment::get().getWorld()->togglePOV(); + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + if ( !player.getClass().getCreatureStats(player).isDead() ) { + if (mControlSwitch["playerviewswitch"]) { + // work around preview mode toggle when pressing Alt+Tab + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + + if (mPreviewPOVDelay <= 0.5 && + (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } else { + if (mPreviewPOVDelay > 0.5) { + //disable preview mode + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + } else if (mPreviewPOVDelay > 0.f) { + MWBase::Environment::get().getWorld()->togglePOV(); + } + mPreviewPOVDelay = 0.f; } - mPreviewPOVDelay = 0.f; } } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 22a641b34..5dd294f90 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -570,15 +570,13 @@ namespace MWMechanics continue; } - if(iter->second->isDead()) - continue; - - iter->second->kill(); - - ++mDeathCount[cls.getId(iter->first)]; + if (iter->second->kill()) + { + ++mDeathCount[cls.getId(iter->first)]; - if(cls.isEssential(iter->first)) - MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); + if(cls.isEssential(iter->first)) + MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); + } } } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index da3ed2523..c8eba20d6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,6 +27,7 @@ #include "security.hpp" #include "../mwrender/animation.hpp" +#include "../mwrender/camera.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1055,10 +1056,19 @@ void CharacterController::forceStateUpdate() } } -void CharacterController::kill() +bool CharacterController::kill() { - if(mDeathState != CharState_None) - return; + if( isDead() ) + { + //player death animation is over: toggle game menu without 'return' option + if( mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() + && !isAnimPlaying(mCurrentDeath) ) + { + MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(true); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + } + return false; + } if(mPtr.getTypeName() == typeid(ESM::NPC).name()) { @@ -1096,6 +1106,10 @@ void CharacterController::kill() if(mAnimation) { + if (mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() + && MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson() ) + MWBase::Environment::get().getWorld()->togglePOV(); + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); @@ -1103,6 +1117,8 @@ void CharacterController::kill() mIdleState = CharState_None; mCurrentIdle.clear(); + + return true; } void CharacterController::resurrect() diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 9e07fca7d..2a5c7bb03 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -190,7 +190,7 @@ public: void skipAnim(); bool isAnimPlaying(const std::string &groupName); - void kill(); + bool kill(); void resurrect(); bool isDead() const { return mDeathState != CharState_None; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b216c789f..7d5162747 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -211,6 +211,11 @@ MWRender::SkyManager* RenderingManager::getSkyManager() return mSkyManager; } +MWRender::Camera* RenderingManager::getCamera() const +{ + return mCamera; +} + MWRender::Objects& RenderingManager::getObjects(){ return *mObjects; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e5dcf0aeb..d6c1ef6c1 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -98,6 +98,8 @@ public: SkyManager* getSkyManager(); Compositors* getCompositors(); + MWRender::Camera* getCamera() const; + void toggleLight(); bool toggleRenderMode(int mode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f64d22122..a900d27ab 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -312,6 +312,8 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); MWBase::Environment::get().getScriptManager()->resetGlobalScripts(); + + MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(false); } @@ -403,6 +405,11 @@ namespace MWWorld return *mPlayer; } + MWRender::Camera* World::getCamera() const + { + return mRendering->getCamera(); + } + const MWWorld::ESMStore& World::getStore() const { return mStore; @@ -1304,7 +1311,7 @@ namespace MWWorld // inform the GUI about focused object MWWorld::Ptr object = getFacedObject (); - MWBase::Environment::get().getWindowManager()->setFocusObject(object); + MWBase::Environment::get().getWindowManager()->setFocusObject(object); // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index c8133441d..2e572d0bb 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -187,6 +187,8 @@ namespace MWWorld virtual Player& getPlayer(); + virtual MWRender::Camera* getCamera() const; + virtual const MWWorld::ESMStore& getStore() const; virtual std::vector& getEsmReader(); From c0d07fbdc9023b76853e2a0b20d9649e9eca1f0a Mon Sep 17 00:00:00 2001 From: mrcheko Date: Sat, 14 Dec 2013 15:07:00 +0200 Subject: [PATCH 02/11] improvement to bug fix http://bugs.openmw.org/issues/428 --- apps/openmw/mwinput/inputmanagerimp.cpp | 45 +++++++++++++------------ apps/openmw/mwmechanics/character.cpp | 19 ++++++----- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9b7fe98bd..efa326a98 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -180,7 +180,9 @@ namespace MWInput switch (action) { case A_GameMenu: - toggleMainMenu (); + if(!(MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).isDead() + && MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_MainMenu ) ) + toggleMainMenu (); break; case A_Screenshot: screenshot(); @@ -300,7 +302,9 @@ namespace MWInput return; // Disable movement in Gui mode - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode() + || MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).isDead() ) + return; // Configure player movement according to keyboard input. Actual movement will @@ -367,29 +371,28 @@ namespace MWInput } } - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); - if ( !player.getClass().getCreatureStats(player).isDead() ) { - if (mControlSwitch["playerviewswitch"]) { - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + + if (mControlSwitch["playerviewswitch"]) { + // work around preview mode toggle when pressing Alt+Tab + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) - { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - } - } else { - if (mPreviewPOVDelay > 0.5) { - //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - } else if (mPreviewPOVDelay > 0.f) { - MWBase::Environment::get().getWorld()->togglePOV(); - } - mPreviewPOVDelay = 0.f; + if (mPreviewPOVDelay <= 0.5 && + (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } else { + if (mPreviewPOVDelay > 0.5) { + //disable preview mode + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + } else if (mPreviewPOVDelay > 0.f) { + MWBase::Environment::get().getWorld()->togglePOV(); } + mPreviewPOVDelay = 0.f; } } + } if (actionIsActive(A_MoveForward) || actionIsActive(A_MoveBackward) || diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c8eba20d6..1c4979e37 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1061,11 +1061,11 @@ bool CharacterController::kill() if( isDead() ) { //player death animation is over: toggle game menu without 'return' option - if( mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() - && !isAnimPlaying(mCurrentDeath) ) + if( mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() + && !isAnimPlaying(mCurrentDeath) && MWBase::Environment::get().getWindowManager()->getMode () != MWGui::GM_MainMenu ) { - MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(true); - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setHealth(0); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); } return false; } @@ -1106,10 +1106,13 @@ bool CharacterController::kill() if(mAnimation) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() - && MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson() ) - MWBase::Environment::get().getWorld()->togglePOV(); - + if (mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) + { + MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(true); + if (MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson() ) + MWBase::Environment::get().getWorld()->togglePOV(); + } + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); From e480e31d1ebcc02771eea694098477511069893f Mon Sep 17 00:00:00 2001 From: mrcheko Date: Fri, 20 Dec 2013 22:37:18 +0200 Subject: [PATCH 03/11] Revert "improvement to bug fix http://bugs.openmw.org/issues/428" This reverts commit c0d07fbdc9023b76853e2a0b20d9649e9eca1f0a. --- apps/openmw/mwinput/inputmanagerimp.cpp | 45 ++++++++++++------------- apps/openmw/mwmechanics/character.cpp | 19 +++++------ 2 files changed, 29 insertions(+), 35 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index efa326a98..9b7fe98bd 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -180,9 +180,7 @@ namespace MWInput switch (action) { case A_GameMenu: - if(!(MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).isDead() - && MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_MainMenu ) ) - toggleMainMenu (); + toggleMainMenu (); break; case A_Screenshot: screenshot(); @@ -302,9 +300,7 @@ namespace MWInput return; // Disable movement in Gui mode - if (MWBase::Environment::get().getWindowManager()->isGuiMode() - || MWWorld::Class::get(mPlayer->getPlayer()).getCreatureStats(mPlayer->getPlayer()).isDead() ) - return; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return; // Configure player movement according to keyboard input. Actual movement will @@ -371,28 +367,29 @@ namespace MWInput } } - - if (mControlSwitch["playerviewswitch"]) { - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + if ( !player.getClass().getCreatureStats(player).isDead() ) { + if (mControlSwitch["playerviewswitch"]) { + // work around preview mode toggle when pressing Alt+Tab + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) - { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - } - } else { - if (mPreviewPOVDelay > 0.5) { - //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - } else if (mPreviewPOVDelay > 0.f) { - MWBase::Environment::get().getWorld()->togglePOV(); + if (mPreviewPOVDelay <= 0.5 && + (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } else { + if (mPreviewPOVDelay > 0.5) { + //disable preview mode + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + } else if (mPreviewPOVDelay > 0.f) { + MWBase::Environment::get().getWorld()->togglePOV(); + } + mPreviewPOVDelay = 0.f; } - mPreviewPOVDelay = 0.f; } } - } if (actionIsActive(A_MoveForward) || actionIsActive(A_MoveBackward) || diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 1c4979e37..c8eba20d6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1061,11 +1061,11 @@ bool CharacterController::kill() if( isDead() ) { //player death animation is over: toggle game menu without 'return' option - if( mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() - && !isAnimPlaying(mCurrentDeath) && MWBase::Environment::get().getWindowManager()->getMode () != MWGui::GM_MainMenu ) + if( mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() + && !isAnimPlaying(mCurrentDeath) ) { - MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setHealth(0); - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); + MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(true); + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); } return false; } @@ -1106,13 +1106,10 @@ bool CharacterController::kill() if(mAnimation) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() ) - { - MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(true); - if (MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson() ) - MWBase::Environment::get().getWorld()->togglePOV(); - } - + if (mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() + && MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson() ) + MWBase::Environment::get().getWorld()->togglePOV(); + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); From b98cfe2d1b887a8c305945fd40e2d0ee7b34bebf Mon Sep 17 00:00:00 2001 From: mrcheko Date: Fri, 20 Dec 2013 22:39:02 +0200 Subject: [PATCH 04/11] Revert "bug fix http://bugs.openmw.org/issues/428" This reverts commit 8dd930cf97fc4a0fee398a31209fabf24ad7fcb1. --- apps/openmw/mwbase/windowmanager.hpp | 2 -- apps/openmw/mwbase/world.hpp | 3 -- apps/openmw/mwgui/mainmenu.cpp | 13 +------- apps/openmw/mwgui/mainmenu.hpp | 4 --- apps/openmw/mwgui/windowmanagerimp.cpp | 5 --- apps/openmw/mwgui/windowmanagerimp.hpp | 3 -- apps/openmw/mwinput/inputmanagerimp.cpp | 37 +++++++++++------------ apps/openmw/mwmechanics/actors.cpp | 14 +++++---- apps/openmw/mwmechanics/character.cpp | 22 ++------------ apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/renderingmanager.cpp | 5 --- apps/openmw/mwrender/renderingmanager.hpp | 2 -- apps/openmw/mwworld/worldimp.cpp | 9 +----- apps/openmw/mwworld/worldimp.hpp | 2 -- 14 files changed, 31 insertions(+), 92 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4ffb44615..c47ad066b 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -202,8 +202,6 @@ namespace MWBase virtual void setSpellVisibility(bool visible) = 0; virtual void setSneakVisibility(bool visible) = 0; - void virtual setMainMenuNoReturn(bool noreturn) = 0; - virtual void activateQuickKey (int index) = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index b1f236bd1..8141af712 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -40,7 +40,6 @@ namespace ESM namespace MWRender { - class Camera; class ExternalRendering; class Animation; } @@ -116,8 +115,6 @@ namespace MWBase virtual MWWorld::Player& getPlayer() = 0; - virtual MWRender::Camera* getCamera() const = 0; - virtual const MWWorld::ESMStore& getStore() const = 0; virtual std::vector& getEsmReader() = 0; diff --git a/apps/openmw/mwgui/mainmenu.cpp b/apps/openmw/mwgui/mainmenu.cpp index e1c72193b..fa7ed2ace 100644 --- a/apps/openmw/mwgui/mainmenu.cpp +++ b/apps/openmw/mwgui/mainmenu.cpp @@ -17,7 +17,6 @@ namespace MWGui MainMenu::MainMenu(int w, int h) : OEngine::GUI::Layout("openmw_mainmenu.layout") , mButtonBox(0) - , mNoReturn(false) { onResChange(w,h); } @@ -34,8 +33,7 @@ namespace MWGui int curH = 0; std::vector buttons; - if(!mNoReturn) - buttons.push_back("return"); + buttons.push_back("return"); buttons.push_back("newgame"); //buttons.push_back("loadgame"); //buttons.push_back("savegame"); @@ -70,15 +68,6 @@ namespace MWGui mButtonBox->setCoord (w/2 - maxwidth/2, h/2 - curH/2, maxwidth, curH); } - void MainMenu::setNoReturn(bool bNoReturn) - { - if (mNoReturn != bNoReturn) - { - mNoReturn = bNoReturn; - onResChange( Settings::Manager::getInt("resolution x", "Video"), Settings::Manager::getInt("resolution y", "Video") ); - } - } - void MainMenu::onButtonClicked(MyGUI::Widget *sender) { MWBase::Environment::get().getSoundManager()->playSound("Menu Click", 1.f, 1.f); diff --git a/apps/openmw/mwgui/mainmenu.hpp b/apps/openmw/mwgui/mainmenu.hpp index a686cb020..4e76a64df 100644 --- a/apps/openmw/mwgui/mainmenu.hpp +++ b/apps/openmw/mwgui/mainmenu.hpp @@ -12,13 +12,9 @@ namespace MWGui void onResChange(int w, int h); - void setNoReturn(bool bNoReturn); - private: MyGUI::Widget* mButtonBox; - bool mNoReturn; - std::map mButtons; void onButtonClicked (MyGUI::Widget* sender); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 69ec11ccc..78986a052 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -880,11 +880,6 @@ namespace MWGui mHud->setSneakVisible(visible); } - void WindowManager::setMainMenuNoReturn(bool noreturn) - { - mMenu->setNoReturn(noreturn); - } - void WindowManager::setDragDrop(bool dragDrop) { mToolTips->setEnabled(!dragDrop); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3d6972718..4f1960295 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -198,9 +198,6 @@ namespace MWGui virtual void setSpellVisibility(bool visible); virtual void setSneakVisibility(bool visible); - //disables 'return' button in the main menu (used when player is dead) - void virtual setMainMenuNoReturn(bool noreturn); - virtual void activateQuickKey (int index); virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 9b7fe98bd..ab2569635 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -367,27 +367,24 @@ namespace MWInput } } - MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); - if ( !player.getClass().getCreatureStats(player).isDead() ) { - if (mControlSwitch["playerviewswitch"]) { - // work around preview mode toggle when pressing Alt+Tab - if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { - - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) - { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - } - } else { - if (mPreviewPOVDelay > 0.5) { - //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - } else if (mPreviewPOVDelay > 0.f) { - MWBase::Environment::get().getWorld()->togglePOV(); - } - mPreviewPOVDelay = 0.f; + if (mControlSwitch["playerviewswitch"]) { + + // work around preview mode toggle when pressing Alt+Tab + if (actionIsActive(A_TogglePOV) && !mInputManager->isModifierHeld(SDL_Keymod(KMOD_ALT))) { + if (mPreviewPOVDelay <= 0.5 && + (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } else { + if (mPreviewPOVDelay > 0.5) { + //disable preview mode + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + } else if (mPreviewPOVDelay > 0.f) { + MWBase::Environment::get().getWorld()->togglePOV(); } + mPreviewPOVDelay = 0.f; } } } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5dd294f90..22a641b34 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -570,13 +570,15 @@ namespace MWMechanics continue; } - if (iter->second->kill()) - { - ++mDeathCount[cls.getId(iter->first)]; + if(iter->second->isDead()) + continue; - if(cls.isEssential(iter->first)) - MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); - } + iter->second->kill(); + + ++mDeathCount[cls.getId(iter->first)]; + + if(cls.isEssential(iter->first)) + MWBase::Environment::get().getWindowManager()->messageBox("#{sKilledEssential}"); } } diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index c8eba20d6..da3ed2523 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -27,7 +27,6 @@ #include "security.hpp" #include "../mwrender/animation.hpp" -#include "../mwrender/camera.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1056,19 +1055,10 @@ void CharacterController::forceStateUpdate() } } -bool CharacterController::kill() +void CharacterController::kill() { - if( isDead() ) - { - //player death animation is over: toggle game menu without 'return' option - if( mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() - && !isAnimPlaying(mCurrentDeath) ) - { - MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(true); - MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu); - } - return false; - } + if(mDeathState != CharState_None) + return; if(mPtr.getTypeName() == typeid(ESM::NPC).name()) { @@ -1106,10 +1096,6 @@ bool CharacterController::kill() if(mAnimation) { - if (mPtr == MWBase::Environment::get().getWorld()->getPlayer().getPlayer() - && MWBase::Environment::get().getWorld()->getCamera()->isFirstPerson() ) - MWBase::Environment::get().getWorld()->togglePOV(); - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); @@ -1117,8 +1103,6 @@ bool CharacterController::kill() mIdleState = CharState_None; mCurrentIdle.clear(); - - return true; } void CharacterController::resurrect() diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 2a5c7bb03..9e07fca7d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -190,7 +190,7 @@ public: void skipAnim(); bool isAnimPlaying(const std::string &groupName); - bool kill(); + void kill(); void resurrect(); bool isDead() const { return mDeathState != CharState_None; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 7d5162747..b216c789f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -211,11 +211,6 @@ MWRender::SkyManager* RenderingManager::getSkyManager() return mSkyManager; } -MWRender::Camera* RenderingManager::getCamera() const -{ - return mCamera; -} - MWRender::Objects& RenderingManager::getObjects(){ return *mObjects; } diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d6c1ef6c1..e5dcf0aeb 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -98,8 +98,6 @@ public: SkyManager* getSkyManager(); Compositors* getCompositors(); - MWRender::Camera* getCamera() const; - void toggleLight(); bool toggleRenderMode(int mode); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a900d27ab..f64d22122 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -312,8 +312,6 @@ namespace MWWorld mWeatherManager = new MWWorld::WeatherManager(mRendering,&mFallback); MWBase::Environment::get().getScriptManager()->resetGlobalScripts(); - - MWBase::Environment::get().getWindowManager()->setMainMenuNoReturn(false); } @@ -405,11 +403,6 @@ namespace MWWorld return *mPlayer; } - MWRender::Camera* World::getCamera() const - { - return mRendering->getCamera(); - } - const MWWorld::ESMStore& World::getStore() const { return mStore; @@ -1311,7 +1304,7 @@ namespace MWWorld // inform the GUI about focused object MWWorld::Ptr object = getFacedObject (); - MWBase::Environment::get().getWindowManager()->setFocusObject(object); + MWBase::Environment::get().getWindowManager()->setFocusObject(object); // retrieve object dimensions so we know where to place the floating label if (!object.isEmpty ()) diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 2e572d0bb..c8133441d 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -187,8 +187,6 @@ namespace MWWorld virtual Player& getPlayer(); - virtual MWRender::Camera* getCamera() const; - virtual const MWWorld::ESMStore& getStore() const; virtual std::vector& getEsmReader(); From d6345bce91e3d65cf69c5f7368e58be348a22763 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Tue, 31 Dec 2013 13:24:20 +0200 Subject: [PATCH 05/11] added npc hit reactions --- apps/openmw/mwclass/npc.cpp | 1 + apps/openmw/mwmechanics/character.cpp | 134 ++++++++++++++------------ apps/openmw/mwmechanics/character.hpp | 11 ++- 3 files changed, 86 insertions(+), 60 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 4187aa8c1..87d98a578 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -604,6 +604,7 @@ namespace MWClass // something, alert the character controller, scripts, etc. MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); + getCreatureStats(ptr).setAttacked(true); if(object.isEmpty()) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 17eff3d02..f4d6feab6 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -65,15 +65,24 @@ struct StateInfo { const char groupname[32]; }; -static const StateInfo sDeathList[] = { - { CharState_Death1, "death1" }, - { CharState_Death2, "death2" }, - { CharState_Death3, "death3" }, - { CharState_Death4, "death4" }, - { CharState_Death5, "death5" }, - { CharState_SwimDeath, "swimdeath" }, +static const std::string sDeathList[] = { + "death1" , + "death2" , + "death3" , + "death4" , + "death5" , + "swimdeath", }; -static const StateInfo *sDeathListEnd = &sDeathList[sizeof(sDeathList)/sizeof(sDeathList[0])]; +static const int sDeathListSize = sizeof(sDeathList)/sizeof(sDeathList[0]); + +static const std::string sHitList[] = { + "hit1" , + "hit2" , + "hit3" , + "hit4" , + "hit5" , +}; +static const int sHitListSize = sizeof(sHitList)/sizeof(sHitList[0]); static const StateInfo sMovementList[] = { { CharState_WalkForward, "walkforward" }, @@ -150,6 +159,38 @@ public: void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) { + if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) + { + mHitState = CharState_Hit; + MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false); + + if(!mAnimation->isPlaying(mCurrentHit)) + { + mAnimation->disable(mCurrentHit); + if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) + && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) + mCurrentHit = "knockdown"; + else + { + int iHit = rand() % sHitListSize; + mCurrentHit = sHitList[iHit]; + } + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, 0); + if(mUpperBodyState == UpperCharState_WeapEquiped) + mUpdateAfterHit = false; + else + mUpdateAfterHit = true; + } + return; + } + else if(!mAnimation->isPlaying(mCurrentHit)) + { + mAnimation->disable(mCurrentHit); + mCurrentHit.erase(); + mHitState = CharState_None; + mUpdateAfterHit = true; + } + const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); if(force || idle != mIdleState) @@ -338,6 +379,23 @@ MWWorld::ContainerStoreIterator CharacterController::getActiveWeapon(NpcStats &s return inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight); } +void CharacterController::playRandomDeath(float startpoint) +{ + if(MWBase::Environment::get().getWorld()->isSwimming(mPtr)) + { + mDeathState = CharState_SwimDeath; + mCurrentDeath = sDeathList[sDeathListSize-1]; //last in the list is 'swimdeath' + } + else + { + int num = rand() % (sDeathListSize-1); + mDeathState = static_cast(CharState_Death1 + num); + mCurrentDeath = sDeathList[num]; + } + + mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, + false, 1.0f, "start", "stop", 0.0f, 0); +} CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim) : mPtr(ptr) @@ -346,6 +404,8 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mMovementState(CharState_None) , mMovementSpeed(0.0f) , mDeathState(CharState_None) + , mHitState(CharState_None) + , mUpdateAfterHit(true) , mUpperBodyState(UpperCharState_Nothing) , mJumpState(JumpState_None) , mWeaponType(WeapType_None) @@ -392,13 +452,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim refreshCurrentAnims(mIdleState, mMovementState, true); if(mDeathState != CharState_None) { - const StateInfo *state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState)); - if(state == sDeathListEnd) - throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState)); - - mCurrentDeath = state->groupname; - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, - false, 1.0f, "start", "stop", 1.0f, 0); + playRandomDeath(1.0f); } } @@ -766,6 +820,8 @@ void CharacterController::update(float duration) bool sneak = cls.getStance(mPtr, MWWorld::Class::Sneak); bool flying = world->isFlying(mPtr); Ogre::Vector3 vec = cls.getMovementVector(mPtr); + if(mHitState != CharState_None && mJumpState == JumpState_None) + vec = Ogre::Vector3(0.0f); Ogre::Vector3 rot = cls.getRotationVector(mPtr); mMovementSpeed = cls.getSpeed(mPtr); @@ -778,6 +834,7 @@ void CharacterController::update(float duration) isrunning = isrunning && std::abs(vec[0])+std::abs(vec[1]) > 0.0f; + // advance athletics if(std::abs(vec[0])+std::abs(vec[1]) > 0.0f && mPtr.getRefData().getHandle() == "player") { @@ -951,7 +1008,7 @@ void CharacterController::update(float duration) } } - if(cls.isNpc()) + if(cls.isNpc() && mUpdateAfterHit) forcestateupdate = updateNpcState(onground, inwater, isrunning, sneak) || forcestateupdate; refreshCurrentAnims(idlestate, movestate, forcestateupdate); @@ -1055,14 +1112,7 @@ void CharacterController::forceStateUpdate() refreshCurrentAnims(mIdleState, mMovementState, true); if(mDeathState != CharState_None) { - const StateInfo *state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState)); - if(state == sDeathListEnd) - throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState)); - - mCurrentDeath = state->groupname; - if(!mAnimation->getInfo(mCurrentDeath)) - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, - false, 1.0f, "start", "stop", 0.0f, 0); + playRandomDeath(0.0f); } } @@ -1071,44 +1121,10 @@ void CharacterController::kill() if(mDeathState != CharState_None) return; - if(mPtr.getTypeName() == typeid(ESM::NPC).name()) - { - const StateInfo *state = NULL; - if(MWBase::Environment::get().getWorld()->isSwimming(mPtr)) - { - mDeathState = CharState_SwimDeath; - state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState)); - if(state == sDeathListEnd) - throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState)); - } - - static const CharacterState deathstates[5] = { - CharState_Death1, CharState_Death2, CharState_Death3, CharState_Death4, CharState_Death5 - }; - std::vector states(&deathstates[0], &deathstates[5]); - - while(states.size() > 1 && (!state || !mAnimation->hasAnimation(state->groupname))) - { - int pos = (int)(rand()/((double)RAND_MAX+1.0)*states.size()); - mDeathState = states[pos]; - states.erase(states.begin()+pos); - - state = std::find_if(sDeathList, sDeathListEnd, FindCharState(mDeathState)); - if(state == sDeathListEnd) - throw std::runtime_error("Failed to find character state "+Ogre::StringConverter::toString(mDeathState)); - } - mCurrentDeath = state->groupname; - } - else - { - mDeathState = CharState_Death1; - mCurrentDeath = "death1"; - } + playRandomDeath(0.0f); if(mAnimation) { - mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, - false, 1.0f, "start", "stop", 0.0f, 0); mAnimation->disable(mCurrentIdle); } diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 817fa2fd5..e0b065cec 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -28,6 +28,7 @@ enum Priority { Priority_Default, Priority_Jump, Priority_Movement, + Priority_Hit, Priority_Weapon, Priority_Torch, @@ -87,7 +88,9 @@ enum CharacterState { CharState_Death3, CharState_Death4, CharState_Death5, - CharState_SwimDeath + CharState_SwimDeath, + + CharState_Hit }; enum WeaponType { @@ -142,6 +145,10 @@ class CharacterController CharacterState mDeathState; std::string mCurrentDeath; + CharacterState mHitState; + std::string mCurrentHit; + bool mUpdateAfterHit;//don't allow attack if it hadn't been started before actor got hit + UpperBodyCharacterState mUpperBodyState; JumpingState mJumpState; @@ -172,6 +179,8 @@ class CharacterController void updateVisibility(); + void playRandomDeath(float startpoint); + public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); From a8fb1ae51c89c21aadaf2e4a3c263a2c6efa8f49 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Tue, 31 Dec 2013 17:55:04 +0200 Subject: [PATCH 06/11] improved, added knockdown after falling --- apps/openmw/mwmechanics/character.cpp | 27 ++++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 1 - 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f4d6feab6..a7ae29824 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -166,7 +166,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(!mAnimation->isPlaying(mCurrentHit)) { - mAnimation->disable(mCurrentHit); if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) mCurrentHit = "knockdown"; @@ -175,20 +174,13 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat int iHit = rand() % sHitListSize; mCurrentHit = sHitList[iHit]; } - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, false, 1, "start", "stop", 0.0f, 0); - if(mUpperBodyState == UpperCharState_WeapEquiped) - mUpdateAfterHit = false; - else - mUpdateAfterHit = true; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } - return; } else if(!mAnimation->isPlaying(mCurrentHit)) { - mAnimation->disable(mCurrentHit); mCurrentHit.erase(); mHitState = CharState_None; - mUpdateAfterHit = true; } const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); @@ -405,7 +397,6 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mMovementSpeed(0.0f) , mDeathState(CharState_None) , mHitState(CharState_None) - , mUpdateAfterHit(true) , mUpperBodyState(UpperCharState_Nothing) , mJumpState(JumpState_None) , mWeaponType(WeapType_None) @@ -554,7 +545,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun bool animPlaying; if(stats.getAttackingOrSpell()) { - if(mUpperBodyState == UpperCharState_WeapEquiped) + if(mUpperBodyState == UpperCharState_WeapEquiped && mHitState == CharState_None) { MWBase::Environment::get().getWorld()->breakInvisibility(mPtr); mAttackType.clear(); @@ -718,9 +709,18 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun if(mUpperBodyState == UpperCharState_EquipingWeap || mUpperBodyState == UpperCharState_FollowStartToFollowStop || mUpperBodyState == UpperCharState_CastingSpell) + { mUpperBodyState = UpperCharState_WeapEquiped; + //don't allow to continue playing hit animation after actor had attacked during it + if(mHitState != CharState_None) + { + mAnimation->disable(mCurrentHit); + mCurrentHit.clear(); + mHitState = CharState_None; + } + } else if(mUpperBodyState == UpperCharState_UnEquipingWeap) - mUpperBodyState = UpperCharState_Nothing; + mUpperBodyState = UpperCharState_Nothing; } else if(complete >= 1.0f) { @@ -938,6 +938,7 @@ void CharacterController::update(float duration) int realHealthLost = healthLost * (1.0f - 0.25 * fatigueTerm); health.setCurrent(health.getCurrent() - realHealthLost); cls.getCreatureStats(mPtr).setHealth(health); + cls.onHit(mPtr, realHealthLost, true, MWWorld::Ptr(), MWWorld::Ptr(), true); // report acrobatics progression if (mPtr.getRefData().getHandle() == "player") @@ -1008,7 +1009,7 @@ void CharacterController::update(float duration) } } - if(cls.isNpc() && mUpdateAfterHit) + if(cls.isNpc()) forcestateupdate = updateNpcState(onground, inwater, isrunning, sneak) || forcestateupdate; refreshCurrentAnims(idlestate, movestate, forcestateupdate); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index e0b065cec..4974b7c08 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -147,7 +147,6 @@ class CharacterController CharacterState mHitState; std::string mCurrentHit; - bool mUpdateAfterHit;//don't allow attack if it hadn't been started before actor got hit UpperBodyCharacterState mUpperBodyState; From 09a0a69b04cf80645dc1bb708f19b11c2bdb715f Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 1 Jan 2014 21:40:31 +0200 Subject: [PATCH 07/11] more improvements --- apps/openmw/mwmechanics/character.cpp | 155 +++++++++++++++++--------- apps/openmw/mwmechanics/character.hpp | 3 + apps/openmw/mwrender/animation.cpp | 15 ++- apps/openmw/mwrender/animation.hpp | 1 + 4 files changed, 122 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index a7ae29824..4a8cf5ea8 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -81,6 +81,7 @@ static const std::string sHitList[] = { "hit3" , "hit4" , "hit5" , + "knockdown" , }; static const int sHitListSize = sizeof(sHitList)/sizeof(sHitList[0]); @@ -161,23 +162,23 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat { if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) { - mHitState = CharState_Hit; MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false); - if(!mAnimation->isPlaying(mCurrentHit)) + if(mHitState == CharState_None) { + mHitState = CharState_Hit; if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) - mCurrentHit = "knockdown"; + mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation else { - int iHit = rand() % sHitListSize; + int iHit = rand() % (sHitListSize-1); mCurrentHit = sHitList[iHit]; } mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } } - else if(!mAnimation->isPlaying(mCurrentHit)) + else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit)) { mCurrentHit.erase(); mHitState = CharState_None; @@ -458,9 +459,27 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) } +void CharacterController::playWeaponAnim(const std::string& start, const std::string& stop, + float speed, bool autoDisable, bool disablePrevious, float startpoint, bool currentWeapon) +{ + std::string weapgroup; + if (currentWeapon) + weapgroup = mCurrentWeapon; + else + getWeaponGroup(mWeaponType, weapgroup); + + if (disablePrevious) + mAnimation->disable(weapgroup); + + mAnimation->play(weapgroup, Priority_Weapon, + MWRender::Animation::Group_All, autoDisable, + speed, start, stop, + startpoint, 0); +} + bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak) { - const MWWorld::Class &cls = MWWorld::Class::get(mPtr); + const MWWorld::Class &cls = MWWorld::Class::get(mPtr); NpcStats &stats = cls.getNpcStats(mPtr); WeaponType weaptype = WeapType_None; MWWorld::InventoryStore &inv = cls.getInventoryStore(mPtr); @@ -490,6 +509,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun { getWeaponGroup(weaptype, weapgroup); mAnimation->showWeapons(false); + mAnimation->play(weapgroup, Priority_Weapon, MWRender::Animation::Group_UpperBody, true, 1.0f, "equip start", "equip stop", 0.0f, 0); @@ -642,7 +662,14 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun { if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_ThowWeapon) + { mAttackType = "shoot"; + mAnimation->play(mCurrentWeapon, Priority_Weapon, + MWRender::Animation::Group_UpperBody, false, + weapSpeed, mAttackType+" start", mAttackType+" attach", + 0.0f, 0); + mUpperBodyState = UpperCharState_StartToAttach; + } else { int attackType = stats.getAttackType(); @@ -655,13 +682,13 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun mAttackType = "slash"; else mAttackType = "thrust"; - } mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); mUpperBodyState = UpperCharState_StartToMinAttack; + } } } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); @@ -711,79 +738,105 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun mUpperBodyState == UpperCharState_CastingSpell) { mUpperBodyState = UpperCharState_WeapEquiped; - //don't allow to continue playing hit animation after actor had attacked during it - if(mHitState != CharState_None) + + if(mHitState != CharState_None) //don't allow to continue playing hit animation after actor had attacked during it { - mAnimation->disable(mCurrentHit); + mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); mCurrentHit.clear(); mHitState = CharState_None; } } else if(mUpperBodyState == UpperCharState_UnEquipingWeap) - mUpperBodyState = UpperCharState_Nothing; + mUpperBodyState = UpperCharState_Nothing; } else if(complete >= 1.0f) { - if(mUpperBodyState == UpperCharState_StartToMinAttack) - { - mAnimation->disable(mCurrentWeapon); - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, - weapSpeed, mAttackType+" min attack", mAttackType+" max attack", - 0.0f, 0); - mUpperBodyState = UpperCharState_MinAttackToMaxAttack; - } - else if(mUpperBodyState == UpperCharState_MaxAttackToMinHit) + std::string start, stop; + switch(mUpperBodyState) { - mAnimation->disable(mCurrentWeapon); - if(mAttackType == "shoot") - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, - weapSpeed, mAttackType+" min hit", mAttackType+" follow start", - 0.0f, 0); - else - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, - weapSpeed, mAttackType+" min hit", mAttackType+" hit", - 0.0f, 0); - mUpperBodyState = UpperCharState_MinHitToHit; + case UpperCharState_StartToMinAttack: + start = mAttackType+" min attack"; + stop = mAttackType+" max attack"; + mUpperBodyState = UpperCharState_MinAttackToMaxAttack; + break; + case UpperCharState_StartToAttach: //only bows, crossbows, throwing weapons here + start = mAttackType+" attach"; + stop = mAttackType+" min attack"; + mUpperBodyState = UpperCharState_StartToMinAttack; + break; + case UpperCharState_MaxAttackToMinHit: + if(mAttackType == "shoot") + { + start = mAttackType+" min hit"; + stop = mAttackType+" release"; + } + else + { + start = mAttackType+" min hit"; + stop = mAttackType+" hit"; + } + mUpperBodyState = UpperCharState_MinHitToHit; + break; + case UpperCharState_MinHitToHit: + if(mAttackType == "shoot") + { + start = mAttackType+" follow start"; + stop = mAttackType+" follow stop"; + } + else + { + float str = stats.getAttackStrength(); + start = mAttackType+((str < 0.5f) ? " small follow start" + : (str < 1.0f) ? " medium follow start" + : " large follow start"); + stop = mAttackType+((str < 0.5f) ? " small follow stop" + : (str < 1.0f) ? " medium follow stop" + : " large follow stop"); + } + mUpperBodyState = UpperCharState_FollowStartToFollowStop; + break; + default: + break; } - else if(mUpperBodyState == UpperCharState_MinHitToHit) + + if(!start.empty()) { mAnimation->disable(mCurrentWeapon); - if(mAttackType == "shoot") + if (mUpperBodyState == UpperCharState_FollowStartToFollowStop) mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, true, - weapSpeed, mAttackType+" follow start", mAttackType+" follow stop", - 0.0f, 0); + weapSpeed, start, stop, 0.0f, 0); else - { - float str = stats.getAttackStrength(); - std::string start = mAttackType+((str < 0.5f) ? " small follow start" - : (str < 1.0f) ? " medium follow start" - : " large follow start"); - std::string stop = mAttackType+((str < 0.5f) ? " small follow stop" - : (str < 1.0f) ? " medium follow stop" - : " large follow stop"); mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, true, + MWRender::Animation::Group_UpperBody, false, weapSpeed, start, stop, 0.0f, 0); - } - mUpperBodyState = UpperCharState_FollowStartToFollowStop; } } + //if playing combat animation and lowerbody is not busy switch to whole body animation + if(weaptype != WeaponType::WeapType_None && complete>0.0f) + { + if( mMovementState != CharState_None || + mJumpState != JumpState_None || + mHitState != CharState_None || + MWBase::Environment::get().getWorld()->isSwimming(mPtr) || + cls.getStance(mPtr, MWWorld::Class::Sneak)) + mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); + else + mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); + } + MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() && mWeaponType != WeapType_Spell && mWeaponType != WeapType_HandToHand) { - mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, - false, 1.0f, "start", "stop", 0.0f, (~(size_t)0)); + mAnimation->play("torch", Priority_Torch, MWRender::Animation::Group_LeftArm, + false, 1.0f, "start", "stop", 0.0f, (~(size_t)0)); } else if (mAnimation->isPlaying("torch")) { - mAnimation->disable("torch"); + mAnimation->disable("torch"); } return forcestateupdate; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 4974b7c08..3cf34b747 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -114,6 +114,7 @@ enum UpperBodyCharacterState { UpperCharState_UnEquipingWeap, UpperCharState_WeapEquiped, UpperCharState_StartToMinAttack, + UpperCharState_StartToAttach, UpperCharState_MinAttackToMaxAttack, UpperCharState_MaxAttackToMinHit, UpperCharState_MinHitToHit, @@ -175,6 +176,8 @@ class CharacterController void clearAnimQueue(); bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak); + void playWeaponAnim(const std::string& start, const std::string& stop, + float speed = 1.0f, bool autoDisable = true, bool disablePrevious = false, float startpoint = 0.0f, bool currentWeapon = true); void updateVisibility(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index de86bcfa7..c7537aa90 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -672,7 +672,20 @@ void Animation::handleTextKey(AnimState &state, const std::string &groupname, co MWBase::Environment::get().getWorld()->castSpell(mPtr); } - +void Animation::changeGroups(const std::string &groupname, int groups) +{ + AnimStateMap::iterator stateiter = mStates.begin(); + stateiter = mStates.find(groupname); + if(stateiter != mStates.end()) + { + if(stateiter->second.mGroups != groups) + { + stateiter->second.mGroups = groups; + resetActiveGroups(); + } + return; + } +} void Animation::play(const std::string &groupname, int priority, int groups, bool autodisable, float speedmult, const std::string &start, const std::string &stop, float startpoint, size_t loops) { if(!mSkelBase || mAnimSources.empty()) diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 72d1c100e..f5f79dd72 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -272,6 +272,7 @@ public: * \param groupname Animation group to disable. */ void disable(const std::string &groupname); + void changeGroups(const std::string &groupname, int group); /** Retrieves the velocity (in units per second) that the animation will move. */ float getVelocity(const std::string &groupname) const; From 16e10cc702e8f133172a1bd3570ef2135505c376 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 1 Jan 2014 22:46:29 +0200 Subject: [PATCH 08/11] error fix --- apps/openmw/mwmechanics/character.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 4a8cf5ea8..aa1a812aa 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -814,7 +814,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun } //if playing combat animation and lowerbody is not busy switch to whole body animation - if(weaptype != WeaponType::WeapType_None && complete>0.0f) + if(weaptype != WeapType_None && complete>0.0f) { if( mMovementState != CharState_None || mJumpState != JumpState_None || From 79e972bdb6b9d5545347a2ef8c2708adebaf34a8 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Thu, 2 Jan 2014 21:54:41 +0200 Subject: [PATCH 09/11] resolved accompanying minor problems --- apps/openmw/mwmechanics/character.cpp | 127 +++++++++++++------------- apps/openmw/mwmechanics/character.hpp | 8 +- 2 files changed, 67 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index aa1a812aa..8e2e348b9 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -160,28 +160,34 @@ public: void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) { - if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) + if(MWWorld::Class::get(mPtr).isActor()) { - MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false); - - if(mHitState == CharState_None) + if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) { - mHitState = CharState_Hit; - if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) - && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) - mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation - else + MWWorld::Class::get(mPtr).getCreatureStats(mPtr).setAttacked(false); + + if(mHitState == CharState_None) { - int iHit = rand() % (sHitListSize-1); - mCurrentHit = sHitList[iHit]; + mHitState = CharState_Hit; + if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) + && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) + { + mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation + mHitState = CharState_KnockDown; + } + else + { + int iHit = rand() % (sHitListSize-1); + mCurrentHit = sHitList[iHit]; + } + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } - } - else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit)) - { - mCurrentHit.erase(); - mHitState = CharState_None; + else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit)) + { + mCurrentHit.erase(); + mHitState = CharState_None; + } } const WeaponInfo *weap = std::find_if(sWeaponTypeList, sWeaponTypeListEnd, FindWeaponType(mWeaponType)); @@ -374,16 +380,24 @@ MWWorld::ContainerStoreIterator CharacterController::getActiveWeapon(NpcStats &s void CharacterController::playRandomDeath(float startpoint) { - if(MWBase::Environment::get().getWorld()->isSwimming(mPtr)) + if(MWWorld::Class::get(mPtr).isNpc()) { - mDeathState = CharState_SwimDeath; - mCurrentDeath = sDeathList[sDeathListSize-1]; //last in the list is 'swimdeath' + if(MWBase::Environment::get().getWorld()->isSwimming(mPtr)) + { + mDeathState = CharState_SwimDeath; + mCurrentDeath = sDeathList[sDeathListSize-1]; //last in the list is 'swimdeath' + } + else + { + int num = rand() % (sDeathListSize-1); + mDeathState = static_cast(CharState_Death1 + num); + mCurrentDeath = sDeathList[num]; + } } else { - int num = rand() % (sDeathListSize-1); - mDeathState = static_cast(CharState_Death1 + num); - mCurrentDeath = sDeathList[num]; + mDeathState = CharState_Death1; + mCurrentDeath = "death1"; } mAnimation->play(mCurrentDeath, Priority_Death, MWRender::Animation::Group_All, @@ -442,6 +456,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim } refreshCurrentAnims(mIdleState, mMovementState, true); + if(mDeathState != CharState_None) { playRandomDeath(1.0f); @@ -458,25 +473,6 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) mPtr = ptr; } - -void CharacterController::playWeaponAnim(const std::string& start, const std::string& stop, - float speed, bool autoDisable, bool disablePrevious, float startpoint, bool currentWeapon) -{ - std::string weapgroup; - if (currentWeapon) - weapgroup = mCurrentWeapon; - else - getWeaponGroup(mWeaponType, weapgroup); - - if (disablePrevious) - mAnimation->disable(weapgroup); - - mAnimation->play(weapgroup, Priority_Weapon, - MWRender::Animation::Group_All, autoDisable, - speed, start, stop, - startpoint, 0); -} - bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak) { const MWWorld::Class &cls = MWWorld::Class::get(mPtr); @@ -662,14 +658,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun { if(mWeaponType == WeapType_Crossbow || mWeaponType == WeapType_BowAndArrow || mWeaponType == WeapType_ThowWeapon) - { mAttackType = "shoot"; - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, - weapSpeed, mAttackType+" start", mAttackType+" attach", - 0.0f, 0); - mUpperBodyState = UpperCharState_StartToAttach; - } else { int attackType = stats.getAttackType(); @@ -682,13 +671,13 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun mAttackType = "slash"; else mAttackType = "thrust"; + } mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, false, weapSpeed, mAttackType+" start", mAttackType+" min attack", 0.0f, 0); - mUpperBodyState = UpperCharState_StartToMinAttack; - } + mUpperBodyState = UpperCharState_StartToMinAttack; } } animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); @@ -739,11 +728,13 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun { mUpperBodyState = UpperCharState_WeapEquiped; - if(mHitState != CharState_None) //don't allow to continue playing hit animation after actor had attacked during it + //don't allow to continue playing hit animation on UpperBody after actor had attacked during it + if(mHitState != CharState_None) { mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); - mCurrentHit.clear(); + //commenting out following 2 lines will give a bit different combat dynamics(slower) mHitState = CharState_None; + mCurrentHit.clear(); } } else if(mUpperBodyState == UpperCharState_UnEquipingWeap) @@ -759,11 +750,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun stop = mAttackType+" max attack"; mUpperBodyState = UpperCharState_MinAttackToMaxAttack; break; - case UpperCharState_StartToAttach: //only bows, crossbows, throwing weapons here - start = mAttackType+" attach"; - stop = mAttackType+" min attack"; - mUpperBodyState = UpperCharState_StartToMinAttack; - break; case UpperCharState_MaxAttackToMinHit: if(mAttackType == "shoot") { @@ -813,17 +799,27 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun } } + if(!animPlaying) + { + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); + } //if playing combat animation and lowerbody is not busy switch to whole body animation - if(weaptype != WeapType_None && complete>0.0f) + if(weaptype != WeapType_None && animPlaying) { if( mMovementState != CharState_None || mJumpState != JumpState_None || mHitState != CharState_None || MWBase::Environment::get().getWorld()->isSwimming(mPtr) || cls.getStance(mPtr, MWWorld::Class::Sneak)) + { + mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); + } else + { + mAnimation->setAccumulation(Ogre::Vector3(0.0f, 0.0f, 0.0f)); mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); + } } MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); @@ -1067,8 +1063,13 @@ void CharacterController::update(float duration) refreshCurrentAnims(idlestate, movestate, forcestateupdate); - rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); - world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); + if(mHitState != CharState_KnockDown) + { + rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); + world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); + } + else + world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); world->queueMovement(mPtr, vec); movement = vec; @@ -1166,7 +1167,7 @@ void CharacterController::forceStateUpdate() refreshCurrentAnims(mIdleState, mMovementState, true); if(mDeathState != CharState_None) { - playRandomDeath(0.0f); + playRandomDeath(); } } @@ -1175,7 +1176,7 @@ void CharacterController::kill() if(mDeathState != CharState_None) return; - playRandomDeath(0.0f); + playRandomDeath(); if(mAnimation) { diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 3cf34b747..b7c29e9ef 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -90,7 +90,8 @@ enum CharacterState { CharState_Death5, CharState_SwimDeath, - CharState_Hit + CharState_Hit, + CharState_KnockDown }; enum WeaponType { @@ -114,7 +115,6 @@ enum UpperBodyCharacterState { UpperCharState_UnEquipingWeap, UpperCharState_WeapEquiped, UpperCharState_StartToMinAttack, - UpperCharState_StartToAttach, UpperCharState_MinAttackToMaxAttack, UpperCharState_MaxAttackToMinHit, UpperCharState_MinHitToHit, @@ -176,12 +176,10 @@ class CharacterController void clearAnimQueue(); bool updateNpcState(bool onground, bool inwater, bool isrunning, bool sneak); - void playWeaponAnim(const std::string& start, const std::string& stop, - float speed = 1.0f, bool autoDisable = true, bool disablePrevious = false, float startpoint = 0.0f, bool currentWeapon = true); void updateVisibility(); - void playRandomDeath(float startpoint); + void playRandomDeath(float startpoint = 0.0f); public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); From 2591ff2d5a4adde5d3e2dc5b80ae1fd94a43bab5 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Mon, 6 Jan 2014 22:00:01 +0200 Subject: [PATCH 10/11] bug repairing --- apps/openmw/mwmechanics/character.cpp | 30 +++++++++++++++++---------- apps/openmw/mwrender/animation.cpp | 15 +++++++++++++- apps/openmw/mwrender/animation.hpp | 1 + 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 299c9dc99..d93ae9519 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -249,7 +249,8 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat else { mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); + //mCurrentJump.clear(); + mCurrentJump = jump; mAnimation->play(jump, Priority_Jump, jumpgroup, true, 1.0f, "loop stop", "stop", 0.0f, 0); } @@ -678,6 +679,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun mUpperBodyState = UpperCharState_StartToMinAttack; } } + animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); } else @@ -708,7 +710,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun } } stats.setAttackStrength(complete); - + mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, false, @@ -725,7 +727,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun mUpperBodyState == UpperCharState_CastingSpell) { mUpperBodyState = UpperCharState_WeapEquiped; - //don't allow to continue playing hit animation on UpperBody after actor had attacked during it if(mHitState != CharState_None) { @@ -748,6 +749,12 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun stop = mAttackType+" max attack"; mUpperBodyState = UpperCharState_MinAttackToMaxAttack; break; + /*case UpperCharState_MinAttackToMaxAttack: + if(!mAnimation->isPlaying(mCurrentWeapon)) + mAnimation->play(mCurrentWeapon, Priority_Weapon, + MWRender::Animation::Group_UpperBody, false, + 1e-9f, mAttackType+" min attack", mAttackType+" max attack", 0.99f, ~0ul); + break;*/ case UpperCharState_MaxAttackToMinHit: if(mAttackType == "shoot") { @@ -797,12 +804,8 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun } } - if(!animPlaying) - { - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); - } //if playing combat animation and lowerbody is not busy switch to whole body animation - if(weaptype != WeapType_None && animPlaying) + if((weaptype != WeapType_None || UpperCharState_UnEquipingWeap) && animPlaying) { if( mMovementState != CharState_None || mJumpState != JumpState_None || @@ -810,15 +813,14 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun MWBase::Environment::get().getWorld()->isSwimming(mPtr) || cls.getStance(mPtr, MWWorld::Class::Sneak)) { - mAnimation->setAccumulation(Ogre::Vector3(1.0f, 1.0f, 0.0f)); mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); } else { - mAnimation->setAccumulation(Ogre::Vector3(0.0f, 0.0f, 0.0f)); mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); } } + MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); if(torch != inv.end() && torch->getTypeName() == typeid(ESM::Light).name() @@ -1001,7 +1003,13 @@ void CharacterController::update(float duration) else { if(!(vec.z > 0.0f)) - mJumpState = JumpState_None; + { + if(!mAnimation->isPlaying(mCurrentJump)) + { + mJumpState = JumpState_None; + mCurrentJump.clear(); + } + } vec.z = 0.0f; if(std::abs(vec.x/2.0f) > std::abs(vec.y)) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 664b0343d..3e682399e 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -562,6 +562,7 @@ void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &posi /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->setPosition(-off); + mAccumRootPosUpd=true; } bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) @@ -851,7 +852,7 @@ void Animation::disable(const std::string &groupname) Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - + mAccumRootPosUpd = false; AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { @@ -945,6 +946,18 @@ Ogre::Vector3 Animation::runAnimation(float duration) updateEffects(duration); + if (!mAccumRootPosUpd) + { + for(stateiter = mStates.begin();stateiter != mStates.end(); stateiter++) + { + if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName()) + { + updatePosition(stateiter->second.mTime, stateiter->second.mTime, movement); + break; + } + } + } + return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index f5f79dd72..013b49400 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -128,6 +128,7 @@ protected: NifOgre::ObjectScenePtr mObjectRoot; AnimSourceList mAnimSources; Ogre::Node *mAccumRoot; + bool mAccumRootPosUpd; Ogre::Node *mNonAccumRoot; NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate; From 46519062d3614f2d5259bb34bc781b22a4d4f263 Mon Sep 17 00:00:00 2001 From: mrcheko Date: Wed, 8 Jan 2014 16:05:14 +0200 Subject: [PATCH 11/11] hit recoils/knockdowns feature --- apps/openmw/mwclass/npc.cpp | 2 +- apps/openmw/mwmechanics/character.cpp | 57 ++++++++------------------- apps/openmw/mwmechanics/character.hpp | 1 + apps/openmw/mwrender/animation.cpp | 14 ------- apps/openmw/mwrender/animation.hpp | 1 - 5 files changed, 19 insertions(+), 56 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index b23cb0814..4fb00a032 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -614,7 +614,7 @@ namespace MWClass // something, alert the character controller, scripts, etc. MWBase::Environment::get().getDialogueManager()->say(ptr, "hit"); - getCreatureStats(ptr).setAttacked(true); + getCreatureStats(ptr).setAttacked(true);//used in CharacterController if(object.isEmpty()) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index d93ae9519..a4b4f2471 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -158,6 +158,7 @@ public: void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterState movement, bool force) { + //hit recoils/knockdown animations handling if(MWWorld::Class::get(mPtr).isActor()) { if(MWWorld::Class::get(mPtr).getCreatureStats(mPtr).getAttacked()) @@ -166,19 +167,20 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat if(mHitState == CharState_None) { - mHitState = CharState_Hit; if(mJumpState != JumpState_None && !MWBase::Environment::get().getWorld()->isFlying(mPtr) && !MWBase::Environment::get().getWorld()->isSwimming(mPtr) ) { - mCurrentHit = sHitList[sHitListSize-1]; //knockdown animation mHitState = CharState_KnockDown; + mCurrentHit = sHitList[sHitListSize-1]; + mAnimation->play(mCurrentHit, Priority_Knockdown, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } else { + mHitState = CharState_Hit; int iHit = rand() % (sHitListSize-1); mCurrentHit = sHitList[iHit]; + mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } - mAnimation->play(mCurrentHit, Priority_Hit, MWRender::Animation::Group_All, true, 1, "start", "stop", 0.0f, 0); } } else if(mHitState != CharState_None && !mAnimation->isPlaying(mCurrentHit)) @@ -249,8 +251,7 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat else { mAnimation->disable(mCurrentJump); - //mCurrentJump.clear(); - mCurrentJump = jump; + mCurrentJump.clear(); mAnimation->play(jump, Priority_Jump, jumpgroup, true, 1.0f, "loop stop", "stop", 0.0f, 0); } @@ -685,7 +686,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun else { animPlaying = mAnimation->getInfo(mCurrentWeapon, &complete); - if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack) + if(mUpperBodyState == UpperCharState_MinAttackToMaxAttack && mHitState != CharState_KnockDown) { if(mAttackType != "shoot") { @@ -710,7 +711,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun } } stats.setAttackStrength(complete); - + mAnimation->disable(mCurrentWeapon); mAnimation->play(mCurrentWeapon, Priority_Weapon, MWRender::Animation::Group_UpperBody, false, @@ -718,6 +719,11 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun 1.0f-complete, 0); mUpperBodyState = UpperCharState_MaxAttackToMinHit; } + else if (mHitState == CharState_KnockDown) + { + mUpperBodyState = UpperCharState_WeapEquiped; + mAnimation->disable(mCurrentWeapon); + } } if(!animPlaying) @@ -728,7 +734,7 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun { mUpperBodyState = UpperCharState_WeapEquiped; //don't allow to continue playing hit animation on UpperBody after actor had attacked during it - if(mHitState != CharState_None) + if(mHitState == CharState_Hit) { mAnimation->changeGroups(mCurrentHit, MWRender::Animation::Group_LowerBody); //commenting out following 2 lines will give a bit different combat dynamics(slower) @@ -749,12 +755,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun stop = mAttackType+" max attack"; mUpperBodyState = UpperCharState_MinAttackToMaxAttack; break; - /*case UpperCharState_MinAttackToMaxAttack: - if(!mAnimation->isPlaying(mCurrentWeapon)) - mAnimation->play(mCurrentWeapon, Priority_Weapon, - MWRender::Animation::Group_UpperBody, false, - 1e-9f, mAttackType+" min attack", mAttackType+" max attack", 0.99f, ~0ul); - break;*/ case UpperCharState_MaxAttackToMinHit: if(mAttackType == "shoot") { @@ -803,23 +803,6 @@ bool CharacterController::updateNpcState(bool onground, bool inwater, bool isrun weapSpeed, start, stop, 0.0f, 0); } } - - //if playing combat animation and lowerbody is not busy switch to whole body animation - if((weaptype != WeapType_None || UpperCharState_UnEquipingWeap) && animPlaying) - { - if( mMovementState != CharState_None || - mJumpState != JumpState_None || - mHitState != CharState_None || - MWBase::Environment::get().getWorld()->isSwimming(mPtr) || - cls.getStance(mPtr, MWWorld::Class::Sneak)) - { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_UpperBody); - } - else - { - mAnimation->changeGroups(mCurrentWeapon, MWRender::Animation::Group_All); - } - } MWWorld::ContainerStoreIterator torch = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedLeft); @@ -1002,14 +985,8 @@ void CharacterController::update(float duration) } else { - if(!(vec.z > 0.0f)) - { - if(!mAnimation->isPlaying(mCurrentJump)) - { - mJumpState = JumpState_None; - mCurrentJump.clear(); - } - } + if(!(vec.z > 0.0f)) + mJumpState = JumpState_None; vec.z = 0.0f; if(std::abs(vec.x/2.0f) > std::abs(vec.y)) @@ -1076,7 +1053,7 @@ void CharacterController::update(float duration) rot *= duration * Ogre::Math::RadiansToDegrees(1.0f); world->rotateObject(mPtr, rot.x, rot.y, rot.z, true); } - else + else //avoid z-rotating for knockdown world->rotateObject(mPtr, rot.x, rot.y, 0.0f, true); world->queueMovement(mPtr, vec); diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index b7c29e9ef..438f542f0 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -30,6 +30,7 @@ enum Priority { Priority_Movement, Priority_Hit, Priority_Weapon, + Priority_Knockdown, Priority_Torch, Priority_Death, diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 3e682399e..8ce751286 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -562,7 +562,6 @@ void Animation::updatePosition(float oldtime, float newtime, Ogre::Vector3 &posi /* Translate the accumulation root back to compensate for the move. */ mAccumRoot->setPosition(-off); - mAccumRootPosUpd=true; } bool Animation::reset(AnimState &state, const NifOgre::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint) @@ -852,7 +851,6 @@ void Animation::disable(const std::string &groupname) Ogre::Vector3 Animation::runAnimation(float duration) { Ogre::Vector3 movement(0.0f); - mAccumRootPosUpd = false; AnimStateMap::iterator stateiter = mStates.begin(); while(stateiter != mStates.end()) { @@ -946,18 +944,6 @@ Ogre::Vector3 Animation::runAnimation(float duration) updateEffects(duration); - if (!mAccumRootPosUpd) - { - for(stateiter = mStates.begin();stateiter != mStates.end(); stateiter++) - { - if(mNonAccumCtrl && stateiter->first == mAnimationValuePtr[0]->getAnimName()) - { - updatePosition(stateiter->second.mTime, stateiter->second.mTime, movement); - break; - } - } - } - return movement; } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 013b49400..f5f79dd72 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -128,7 +128,6 @@ protected: NifOgre::ObjectScenePtr mObjectRoot; AnimSourceList mAnimSources; Ogre::Node *mAccumRoot; - bool mAccumRootPosUpd; Ogre::Node *mNonAccumRoot; NifOgre::NodeTargetValue *mNonAccumCtrl; Ogre::Vector3 mAccumulate;