bool Engine::MultiplyAndPush(NextAction** actions, float forceRelevance, bool skipPrerequisites, Event event, const char* pushType) { bool pushed = false; if (actions) { for (int j=0; j<10; j++) // TODO: remove 10 { NextAction* nextAction = actions[j]; if (nextAction) { ActionNode* action = CreateActionNode(nextAction->getName()); InitializeAction(action); float k = nextAction->getRelevance(); if (forceRelevance > 0.0f) { k = forceRelevance; } if (k > 0) { LogAction("PUSH:%s - %f (%s)", action->getName().c_str(), k, pushType); queue.Push(new ActionBasket(action, k, skipPrerequisites, event)); pushed = true; } delete nextAction; } else break; } delete actions; } return pushed; }
bool Engine::DoNextAction(Unit* unit, int depth) { LogAction("--- AI Tick ---"); if (sPlayerbotAIConfig.logValuesPerTick) LogValues(); bool actionExecuted = false; ActionBasket* basket = NULL; time_t currentTime = time(0); aiObjectContext->Update(); ProcessTriggers(); int iterations = 0; int iterationsPerTick = queue.Size() * sPlayerbotAIConfig.iterationsPerTick; do { basket = queue.Peek(); if (basket) { if (++iterations > iterationsPerTick) break; float relevance = basket->getRelevance(); // just for reference bool skipPrerequisites = basket->isSkipPrerequisites(); Event event = basket->getEvent(); // NOTE: queue.Pop() deletes basket ActionNode* actionNode = queue.Pop(); Action* action = InitializeAction(actionNode); if (!action) { LogAction("A:%s - UNKNOWN", actionNode->getName().c_str()); } else if (action->isUseful()) { for (list<Multiplier*>::iterator i = multipliers.begin(); i!= multipliers.end(); i++) { Multiplier* multiplier = *i; relevance *= multiplier->GetValue(action); if (!relevance) { LogAction("Multiplier %s made action %s useless", multiplier->getName().c_str(), action->getName().c_str()); break; } } if (action->isPossible() && relevance) { if (!skipPrerequisites) { LogAction("A:%s - PREREQ", action->getName().c_str()); if (MultiplyAndPush(actionNode->getPrerequisites(), relevance + 0.02, false, event, "prereq")) { PushAgain(actionNode, relevance + 0.01, event); continue; } } actionExecuted = ListenAndExecute(action, event); if (actionExecuted) { LogAction("A:%s - OK", action->getName().c_str()); MultiplyAndPush(actionNode->getContinuers(), 0, false, event, "cont"); lastRelevance = relevance; delete actionNode; break; } else { LogAction("A:%s - FAILED", action->getName().c_str()); MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event, "alt"); } } else { LogAction("A:%s - IMPOSSIBLE", action->getName().c_str()); MultiplyAndPush(actionNode->getAlternatives(), relevance + 0.03, false, event, "alt"); } } else { lastRelevance = relevance; LogAction("A:%s - USELESS", action->getName().c_str()); } delete actionNode; } } while (basket); if (!basket) { lastRelevance = 0.0f; PushDefaultActions(); if (queue.Peek() && depth < 2) return DoNextAction(unit, depth + 1); } if (time(0) - currentTime > 1) { LogAction("too long execution"); } if (!actionExecuted) LogAction("no actions executed"); return actionExecuted; }