From 4559e932ae0b9d1319b6d0fc99396c819a51dfb7 Mon Sep 17 00:00:00 2001 From: gus Date: Mon, 18 Nov 2013 12:33:09 +0100 Subject: [PATCH] AI packages have priority and combat is triggered in actor.cpp using the Hostile setting in CreaturesState --- apps/openmw/mwmechanics/actors.cpp | 38 +++++++ apps/openmw/mwmechanics/aicombat.cpp | 141 +++++++++++++------------ apps/openmw/mwmechanics/aicombat.hpp | 2 + apps/openmw/mwmechanics/aipackage.hpp | 3 + apps/openmw/mwmechanics/aisequence.cpp | 68 +++--------- apps/openmw/mwmechanics/aisequence.hpp | 6 +- 6 files changed, 135 insertions(+), 123 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 03a161e86..cbd369a81 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -22,6 +22,11 @@ #include "creaturestats.hpp" #include "movement.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" + +#include "aicombat.hpp" + namespace MWMechanics { void Actors::updateActor (const MWWorld::Ptr& ptr, float duration) @@ -35,6 +40,39 @@ namespace MWMechanics { // AI CreatureStats& creatureStats = MWWorld::Class::get (ptr).getCreatureStats (ptr); + + //engage combat or not? + if(ptr != MWBase::Environment::get().getWorld()->getPlayer().getPlayer() && !creatureStats.isHostile()) + { + ESM::Position playerpos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); + ESM::Position actorpos = ptr.getRefData().getPosition(); + float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) + +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) + +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); + float fight = ptr.getClass().getCreatureStats(ptr).getAiSetting(1); + float disp = 100; //creatures don't have disposition, so set it to 100 by default + if(ptr.getTypeName() == typeid(ESM::NPC).name()) + { + disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(ptr); + } + bool LOS = MWBase::Environment::get().getWorld()->getLOS(ptr,MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); + if( ( (fight == 100 ) + || (fight >= 95 && d <= 3000) + || (fight >= 90 && d <= 2000) + || (fight >= 80 && d <= 1000) + || (fight >= 80 && disp <= 40) + || (fight >= 70 && disp <= 35 && d <= 1000) + || (fight >= 60 && disp <= 30 && d <= 1000) + || (fight >= 50 && disp == 0) + || (fight >= 40 && disp <= 10 && d <= 500) ) + && LOS + ) + { + creatureStats.getAiSequence().stack(AiCombat("player")); + creatureStats.setHostile(true); + } + } + creatureStats.getAiSequence().execute (ptr,duration); // fatigue restoration diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index aeddb4781..39a97df6c 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -34,103 +34,110 @@ namespace MWMechanics bool AiCombat::execute (const MWWorld::Ptr& actor,float duration) { + if(!MWWorld::Class::get(actor).getCreatureStats(actor).isHostile()) return true; + const MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getPtr(mTargetId, false); if(MWWorld::Class::get(actor).getCreatureStats(actor).getHealth().getCurrent() <= 0) return true; if(actor.getTypeName() == typeid(ESM::NPC).name()) { + MWWorld::Class::get(actor). MWWorld::Class::get(actor).setStance(actor, MWWorld::Class::Run,true); MWMechanics::DrawState_ state = MWWorld::Class::get(actor).getNpcStats(actor).getDrawState(); if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing) MWWorld::Class::get(actor).getNpcStats(actor).setDrawState(MWMechanics::DrawState_Weapon); //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true); + } + ESM::Position pos = actor.getRefData().getPosition(); + const ESM::Pathgrid *pathgrid = + MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); - ESM::Position pos = actor.getRefData().getPosition(); - const ESM::Pathgrid *pathgrid = - MWBase::Environment::get().getWorld()->getStore().get().search(*actor.getCell()->mCell); + float xCell = 0; + float yCell = 0; - float xCell = 0; - float yCell = 0; + if (actor.getCell()->mCell->isExterior()) + { + xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; + yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + } - if (actor.getCell()->mCell->isExterior()) + ESM::Pathgrid::Point dest; + dest.mX = target.getRefData().getPosition().pos[0]; + dest.mY = target.getRefData().getPosition().pos[1]; + dest.mZ = target.getRefData().getPosition().pos[2]; + + ESM::Pathgrid::Point start; + start.mX = pos.pos[0]; + start.mY = pos.pos[1]; + start.mZ = pos.pos[2]; + + mTimer2 = mTimer2 + duration; + + if(!mPathFinder.isPathConstructed()) + mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); + else + { + mPathFinder2.buildPath(start, dest, pathgrid, xCell, yCell, true); + ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); + if((mTimer2 > 0.25)&&(mPathFinder2.getPathSize() < mPathFinder.getPathSize() || + (dest.mX - lastPt.mX)*(dest.mX - lastPt.mX)+(dest.mY - lastPt.mY)*(dest.mY - lastPt.mY)+(dest.mZ - lastPt.mZ)*(dest.mZ - lastPt.mZ) > 200*200)) { - xCell = actor.getCell()->mCell->mData.mX * ESM::Land::REAL_SIZE; - yCell = actor.getCell()->mCell->mData.mY * ESM::Land::REAL_SIZE; + mTimer2 = 0; + mPathFinder = mPathFinder2; } + } - ESM::Pathgrid::Point dest; - dest.mX = target.getRefData().getPosition().pos[0]; - dest.mY = target.getRefData().getPosition().pos[1]; - dest.mZ = target.getRefData().getPosition().pos[2]; + mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); - ESM::Pathgrid::Point start; - start.mX = pos.pos[0]; - start.mY = pos.pos[1]; - start.mZ = pos.pos[2]; + float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - mTimer2 = mTimer2 + duration; - if(!mPathFinder.isPathConstructed()) - mPathFinder.buildPath(start, dest, pathgrid, xCell, yCell, true); + float range = 100; + MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); + if((dest.mX - start.mX)*(dest.mX - start.mX)+(dest.mY - start.mY)*(dest.mY - start.mY)+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) + < range*range) + { + float directionX = dest.mX - start.mX; + float directionY = dest.mY - start.mY; + float directionResult = sqrt(directionX * directionX + directionY * directionY); + + zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); + MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); + + mPathFinder.clearPath(); + + if(mTimer == 0) + { + MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); + //mTimer = mTimer + duration; + } + if( mTimer > 1) + { + MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true); + mTimer = 0; + } else { - mPathFinder2.buildPath(start, dest, pathgrid, xCell, yCell, true); - ESM::Pathgrid::Point lastPt = mPathFinder.getPath().back(); - if((mTimer2 > 0.25)&&(mPathFinder2.getPathSize() < mPathFinder.getPathSize() || - (dest.mX - lastPt.mX)*(dest.mX - lastPt.mX)+(dest.mY - lastPt.mY)*(dest.mY - lastPt.mY)+(dest.mZ - lastPt.mZ)*(dest.mZ - lastPt.mZ) > 200*200)) - { - mTimer2 = 0; - mPathFinder = mPathFinder2; - } + mTimer = mTimer + duration; } - - mPathFinder.checkPathCompleted(pos.pos[0],pos.pos[1],pos.pos[2]); - float zAngle = mPathFinder.getZAngleToNext(pos.pos[0], pos.pos[1]); - MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 1; - - - float range = 100; - MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); - if((dest.mX - start.mX)*(dest.mX - start.mX)+(dest.mY - start.mY)*(dest.mY - start.mY)+(dest.mZ - start.mZ)*(dest.mZ - start.mZ) - < range*range) - { - float directionX = dest.mX - start.mX; - float directionY = dest.mY - start.mY; - float directionResult = sqrt(directionX * directionX + directionY * directionY); - - zAngle = Ogre::Radian( acos(directionY / directionResult) * sgn(asin(directionX / directionResult)) ).valueDegrees(); - MWBase::Environment::get().getWorld()->rotateObject(actor, 0, 0, zAngle, false); - - mPathFinder.clearPath(); - - if(mTimer == 0) - { - MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(false); - //mTimer = mTimer + duration; - } - if( mTimer > 1) - { - MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(true); - mTimer = 0; - } - else - { - mTimer = mTimer + duration; - } - - MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; - //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(!MWWorld::Class::get(actor).getCreatureStats(actor).getAttackingOrSpell()); - } + MWWorld::Class::get(actor).getMovementSettings(actor).mPosition[1] = 0; + //MWWorld::Class::get(actor).getCreatureStats(actor).setAttackingOrSpell(!MWWorld::Class::get(actor).getCreatureStats(actor).getAttackingOrSpell()); } return false; } int AiCombat::getTypeId() const { - return 2; + return 5; + } + + unsigned int AiCombat::getPriority() const + { + return 1; } AiCombat *MWMechanics::AiCombat::clone() const diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index eed92ef3a..fa71e261f 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -21,6 +21,8 @@ namespace MWMechanics virtual int getTypeId() const; + virtual unsigned int getPriority() const; + private: std::string mTargetId; diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index 794708f22..5832198da 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -22,6 +22,9 @@ namespace MWMechanics virtual int getTypeId() const = 0; ///< 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate + + virtual unsigned int getPriority() const {return 0;} + ///< higher number is higher priority (0 beeing the lowest) }; } diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 994a7a932..d5fb76ede 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -17,19 +17,14 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" -#include "../mwbase/mechanicsmanager.hpp" - void MWMechanics::AiSequence::copy (const AiSequence& sequence) { for (std::list::const_iterator iter (sequence.mPackages.begin()); iter!=sequence.mPackages.end(); ++iter) mPackages.push_back ((*iter)->clone()); - mCombat = sequence.mCombat; - mCombatPackage = 0; - if(sequence.mCombat) mCombatPackage = sequence.mCombatPackage->clone(); } -MWMechanics::AiSequence::AiSequence() : mDone (false), mCombat (false), mCombatPackage (0) {} +MWMechanics::AiSequence::AiSequence() : mDone (false) {} MWMechanics::AiSequence::AiSequence (const AiSequence& sequence) : mDone (false) { @@ -69,48 +64,15 @@ void MWMechanics::AiSequence::execute (const MWWorld::Ptr& actor,float duration) { if(actor != MWBase::Environment::get().getWorld()->getPlayer().getPlayer()) { - if(mCombat) + if (!mPackages.empty()) { - mCombatPackage->execute(actor,duration); - } - else - { - if(actor.getTypeName() == typeid(ESM::NPC).name()) + if (mPackages.front()->execute (actor,duration)) { - ESM::Position playerpos = MWBase::Environment::get().getWorld()->getPlayer().getPlayer().getRefData().getPosition(); - ESM::Position actorpos = actor.getRefData().getPosition(); - float d = sqrt((actorpos.pos[0] - playerpos.pos[0])*(actorpos.pos[0] - playerpos.pos[0]) - +(actorpos.pos[1] - playerpos.pos[1])*(actorpos.pos[1] - playerpos.pos[1]) - +(actorpos.pos[2] - playerpos.pos[2])*(actorpos.pos[2] - playerpos.pos[2])); - float fight = actor.getClass().getCreatureStats(actor).getAiSetting(1); - float disp = MWBase::Environment::get().getMechanicsManager()->getDerivedDisposition(actor); - bool LOS = MWBase::Environment::get().getWorld()->getLOS(actor,MWBase::Environment::get().getWorld()->getPlayer().getPlayer()); - if( ( (fight == 100 ) - || (fight >= 95 && d <= 3000) - || (fight >= 90 && d <= 2000) - || (fight >= 80 && d <= 1000) - || (fight >= 80 && disp <= 40) - || (fight >= 70 && disp <= 35 && d <= 1000) - || (fight >= 60 && disp <= 30 && d <= 1000) - || (fight >= 50 && disp == 0) - || (fight >= 40 && disp <= 10 && d <= 500) ) - && LOS - ) - { - mCombat = true; - mCombatPackage = new AiCombat("player"); - } - } - if (!mPackages.empty()) - { - if (mPackages.front()->execute (actor,duration)) - { - mPackages.erase (mPackages.begin()); - mDone = true; - } - else - mDone = false; + mPackages.erase (mPackages.begin()); + mDone = true; } + else + mDone = false; } } } @@ -119,18 +81,20 @@ void MWMechanics::AiSequence::clear() { for (std::list::const_iterator iter (mPackages.begin()); iter!=mPackages.end(); ++iter) delete *iter; - - if(mCombatPackage) - { - delete mCombatPackage; - mCombatPackage = 0; - } + mPackages.clear(); } void MWMechanics::AiSequence::stack (const AiPackage& package) { - mPackages.push_front (package.clone()); + for(std::list::iterator it = mPackages.begin(); it != mPackages.end(); it++) + { + if(mPackages.front()->getPriority() <= package.getPriority()) + mPackages.insert(it,package.clone()); + } + + if(mPackages.empty()) + mPackages.push_front (package.clone()); } void MWMechanics::AiSequence::queue (const AiPackage& package) diff --git a/apps/openmw/mwmechanics/aisequence.hpp b/apps/openmw/mwmechanics/aisequence.hpp index ea2a048f1..0976ef099 100644 --- a/apps/openmw/mwmechanics/aisequence.hpp +++ b/apps/openmw/mwmechanics/aisequence.hpp @@ -18,8 +18,6 @@ namespace MWMechanics class AiSequence { std::list mPackages; - AiPackage* mCombatPackage; - bool mCombat; bool mDone; @@ -36,7 +34,7 @@ namespace MWMechanics virtual ~AiSequence(); int getTypeId() const; - ///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate + ///< -1: None, 0: Wanter, 1 Travel, 2 Escort, 3 Follow, 4 Activate, 5 Combat bool isPackageDone() const; ///< Has a package been completed during the last update? @@ -46,7 +44,7 @@ namespace MWMechanics void clear(); ///< Remove all packages. - + void stack (const AiPackage& package); ///< Add \a package to the front of the sequence (suspends current package)