예제 #1
0
void AiSequence::fastForward(const MWWorld::Ptr& actor, AiState& state)
{
    if (!mPackages.empty())
    {
        MWMechanics::AiPackage* package = mPackages.front();
        package->fastForward(actor, state);
    }
}
예제 #2
0
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;
            }
        }
    }
}
예제 #3
0
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);
    }
}
예제 #4
0
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();
        }
    }
}