void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state) { if (!mPackages.empty()) { MWMechanics::AiPackage* package = mPackages.front(); package->fastForward(actor, state); } }
void AiSequence::execute (const MWWorld::Ptr& actor,float duration) { if(actor != MWBase::Environment::get().getWorld()->getPlayerPtr()) { if (!mPackages.empty()) { MWMechanics::AiPackage* package = mPackages.front(); mLastAiPackage = package->getTypeId(); // if active package is combat one, choose nearest target if (mLastAiPackage == AiPackage::TypeIdCombat) { std::list<AiPackage *>::iterator itActualCombat; float nearestDist = std::numeric_limits<float>::max(); Ogre::Vector3 vActorPos = Ogre::Vector3(actor.getRefData().getPosition().pos); for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();) { if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; MWWorld::Ptr target = static_cast<const AiCombat *>(*it)->getTarget(); // target disappeared (e.g. summoned creatures) if (target.isEmpty()) { delete *it; it = mPackages.erase(it); } else { ESM::Position &targetPos = target.getRefData().getPosition(); float distTo = (Ogre::Vector3(targetPos.pos) - vActorPos).length(); if (distTo < nearestDist) { nearestDist = distTo; itActualCombat = it; } ++it; } } if (!mPackages.empty()) { if (nearestDist < std::numeric_limits<float>::max() && mPackages.begin() != itActualCombat) { // move combat package with nearest target to the front mPackages.splice(mPackages.begin(), mPackages, itActualCombat); } package = mPackages.front(); mLastAiPackage = package->getTypeId(); } else { mDone = true; return; } } if (package->execute (actor,duration)) { // To account for the rare case where AiPackage::execute() queued another AI package // (e.g. AiPursue executing a dialogue script that uses startCombat) std::list<MWMechanics::AiPackage*>::iterator toRemove = std::find(mPackages.begin(), mPackages.end(), package); mPackages.erase(toRemove); delete package; mDone = true; } else { mDone = false; } } } }
void AiSequence::readState(const ESM::AiSequence::AiSequence &sequence) { if (!sequence.mPackages.empty()) clear(); for (std::vector<ESM::AiSequence::AiPackageContainer>::const_iterator it = sequence.mPackages.begin(); it != sequence.mPackages.end(); ++it) { MWMechanics::AiPackage* package = NULL; switch (it->mType) { case ESM::AiSequence::Ai_Wander: { package = new AiWander(static_cast<ESM::AiSequence::AiWander*>(it->mPackage)); break; } case ESM::AiSequence::Ai_Travel: { package = new AiTravel(static_cast<ESM::AiSequence::AiTravel*>(it->mPackage)); break; } case ESM::AiSequence::Ai_Escort: { package = new AiEscort(static_cast<ESM::AiSequence::AiEscort*>(it->mPackage)); break; } case ESM::AiSequence::Ai_Follow: { package = new AiFollow(static_cast<ESM::AiSequence::AiFollow*>(it->mPackage)); break; } case ESM::AiSequence::Ai_Activate: { package = new AiActivate(static_cast<ESM::AiSequence::AiActivate*>(it->mPackage)); break; } case ESM::AiSequence::Ai_Combat: { package = new AiCombat(static_cast<ESM::AiSequence::AiCombat*>(it->mPackage)); break; } case ESM::AiSequence::Ai_Pursue: { package = new AiPursue(static_cast<ESM::AiSequence::AiPursue*>(it->mPackage)); break; } default: break; } if (!package) continue; // remove previous packages if required if (package->shouldCancelPreviousAi()) { for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();) { if((*it)->canCancel()) it = mPackages.erase(it); else ++it; } } mPackages.push_back(package); } }
void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& characterController, float duration) { if(actor != getPlayer()) { if (mPackages.empty()) { mLastAiPackage = -1; return; } MWMechanics::AiPackage* package = mPackages.front(); int packageTypeId = package->getTypeId(); // workaround ai packages not being handled as in the vanilla engine if (isActualAiPackage(packageTypeId)) mLastAiPackage = packageTypeId; // if active package is combat one, choose nearest target if (packageTypeId == AiPackage::TypeIdCombat) { std::list<AiPackage *>::iterator itActualCombat; float nearestDist = std::numeric_limits<float>::max(); osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); float bestRating = 0.f; for(std::list<AiPackage *>::iterator it = mPackages.begin(); it != mPackages.end();) { if ((*it)->getTypeId() != AiPackage::TypeIdCombat) break; MWWorld::Ptr target = static_cast<const AiCombat *>(*it)->getTarget(); // target disappeared (e.g. summoned creatures) if (target.isEmpty()) { delete *it; it = mPackages.erase(it); } else { float rating = MWMechanics::getBestActionRating(actor, target); const ESM::Position &targetPos = target.getRefData().getPosition(); float distTo = (targetPos.asVec3() - vActorPos).length(); // Small threshold for changing target if (it == mPackages.begin()) distTo = std::max(0.f, distTo - 50.f); // if a target has higher priority than current target or has same priority but closer if (rating > bestRating || ((distTo < nearestDist) && rating == bestRating)) { nearestDist = distTo; itActualCombat = it; bestRating = rating; } ++it; } } if (!mPackages.empty()) { if (nearestDist < std::numeric_limits<float>::max() && mPackages.begin() != itActualCombat) { // move combat package with nearest target to the front mPackages.splice(mPackages.begin(), mPackages, itActualCombat); } package = mPackages.front(); } } try { if (package->execute (actor, characterController, mAiState, duration)) { // Put repeating noncombat AI packages on the end of the stack so they can be used again if (isActualAiPackage(packageTypeId) && (mRepeat || package->getRepeat())) { package->reset(); mPackages.push_back(package->clone()); } // To account for the rare case where AiPackage::execute() queued another AI package // (e.g. AiPursue executing a dialogue script that uses startCombat) std::list<MWMechanics::AiPackage*>::iterator toRemove = std::find(mPackages.begin(), mPackages.end(), package); mPackages.erase(toRemove); delete package; if (isActualAiPackage(packageTypeId)) mDone = true; } else { mDone = false; } } catch (std::exception& e) { Log(Debug::Error) << "Error during AiSequence::execute: " << e.what(); } } }