void AbstractTask::UpdateStatsDistances(const GeoPoint &location, const bool full_update) { stats.total.remaining.set_distance(ScanDistanceRemaining(location)); const TaskPoint *active = GetActiveTaskPoint(); if (active != NULL) { stats.current_leg.location_remaining = active->GetLocationRemaining(); stats.current_leg.vector_remaining = active->GetVectorRemaining(location); } else { stats.current_leg.location_remaining = GeoPoint::Invalid(); stats.current_leg.vector_remaining = GeoVector::Invalid(); } if (full_update) stats.distance_nominal = ScanDistanceNominal(); ScanDistanceMinMax(location, full_update, &stats.distance_min, &stats.distance_max); stats.total.travelled.set_distance(ScanDistanceTravelled(location)); stats.total.planned.set_distance(ScanDistancePlanned()); if (IsScored()) { if (!TaskStarted()) stats.distance_scored = fixed_zero; else if (!TaskFinished()) stats.distance_scored = ScanDistanceScored(location); } else stats.distance_scored = fixed_zero; }
AircraftState OrderedTask::GetFinishState() const { if (HasFinish() && TaskFinished()) return taskpoint_finish->GetEnteredState(); AircraftState null_state; return null_state; }
void AbstractTask::UpdateStatsTimes(const AircraftState &state) { // default for tasks with no start time... stats.Time = state.time; if (!TaskFinished()) { stats.total.SetTimes(ScanTotalStartTime(state), state); stats.current_leg.SetTimes(ScanLegStartTime(state),state); } }
//---------------------------------------------------------------------------------------------------------------- void CBot_HL2DM::Think() { if ( !m_bAlive ) { m_cCmd.buttons = rand() & IN_ATTACK; // Force bot to respawn by hitting randomly attack button. return; } bool bForceNewTask = false; // Check for move failure. if ( m_bMoveFailure || m_bStuck ) { if ( iCurrentWaypoint == m_iFailWaypoint ) m_iFailsCount++; else { m_iFailWaypoint = iCurrentWaypoint; m_iFailsCount = 1; } if ( m_iFailsCount >= 3 ) { BotMessage("Failed to follow path on same waypoint %d 3 times, marking task as finished.", iCurrentWaypoint); TaskFinished(); m_bNeedTaskCheck = bForceNewTask = true; m_iFailsCount = 0; m_iFailWaypoint = -1; } else if ( m_bMoveFailure ) { // Recalculate the route. m_iDestinationWaypoint = m_iTaskDestination; m_bNeedMove = m_bUseNavigatorToMove = m_bDestinationChanged = true; } m_bMoveFailure = m_bStuck = false; } // Check if needs to add new tasks. Objectives have more priority than task, but not when bot flees. if ( m_bNeedTaskCheck ) { m_bNeedTaskCheck = false; if ( bForceNewTask || m_bFlee || (!m_bObjectiveChanged && (m_iObjective == EBotChatUnknown)) ) CheckNewTasks(bForceNewTask); } if ( m_bFlee ) m_bNeedSprint = true; // Force bot to move rapidly. TODO: check if stops. }
void AbstractTask::UpdateStatsSpeeds(const AircraftState &state, const AircraftState &state_last) { if (!TaskFinished()) { if (TaskStarted()) { const fixed dt = state.time - state_last.time; stats_computer.total.CalcSpeeds(stats.total, dt); stats_computer.current_leg.CalcSpeeds(stats.current_leg, dt); } else { stats_computer.total.Reset(stats.total); stats_computer.current_leg.Reset(stats.current_leg); } } }
bool OrderedTask::CheckTransitions(const AircraftState &state, const AircraftState &state_last) { if (!taskpoint_start) return false; taskpoint_start->ScanActive(*task_points[active_task_point]); if (!state.flying) return false; const int n_task = task_points.size(); if (!n_task) return false; FlatBoundingBox bb_last(task_projection.project(state_last.location),1); FlatBoundingBox bb_now(task_projection.project(state.location),1); bool last_started = TaskStarted(); const bool last_finished = TaskFinished(); const int t_min = max(0, (int)active_task_point - 1); const int t_max = min(n_task - 1, (int)active_task_point); bool full_update = false; for (int i = t_min; i <= t_max; i++) { bool transition_enter = false; bool transition_exit = false; if (i==0) { full_update |= CheckTransitionOptionalStart(state, state_last, bb_now, bb_last, transition_enter, transition_exit, last_started); } full_update |= CheckTransitionPoint(*task_points[i], state, state_last, bb_now, bb_last, transition_enter, transition_exit, last_started, i == 0); if (i == (int)active_task_point) { const bool last_request_armed = task_advance.NeedToArm(); if (task_advance.CheckReadyToAdvance(*task_points[i], state, transition_enter, transition_exit)) { task_advance.SetArmed(false); if (i + 1 < n_task) { i++; SetActiveTaskPoint(i); taskpoint_start->ScanActive(*task_points[active_task_point]); if (task_events != NULL) task_events->ActiveAdvanced(*task_points[i], i); // on sector exit, must update samples since start sector // exit transition clears samples full_update = true; } } else if (!last_request_armed && task_advance.NeedToArm()) { if (task_events != NULL) task_events->RequestArm(*task_points[i]); } } } taskpoint_start->ScanActive(*task_points[active_task_point]); stats.task_finished = TaskFinished(); stats.task_started = TaskStarted(); if (stats.task_started) taskpoint_finish->set_fai_finish_height(GetStartState().altitude - fixed(1000)); if (task_events != NULL) { if (stats.task_started && !last_started) task_events->TaskStart(); if (stats.task_finished && !last_finished) task_events->TaskFinish(); } return full_update; }
//---------------------------------------------------------------------------------------------------------------- void CBot_HL2DM::CheckNewTasks( bool bForceTaskChange ) { TBotTaskHL2DM iNewTask = EBotTaskInvalid; bool bForce = bForceTaskChange || (m_iCurrentTask == EBotTaskInvalid); const CWeapon* pWeapon = m_aWeapons[m_iBestWeapon].GetBaseWeapon(); TBotIntelligence iWeaponPreference = m_iIntelligence; bool bNeedHealth = CMod::HasMapItems(EEntityTypeHealth) && ( m_pPlayerInfo->GetHealth() < CUtil::iPlayerMaxHealth ); bool bNeedHealthBad = bNeedHealth && ( m_pPlayerInfo->GetHealth() < (CUtil::iPlayerMaxHealth/2) ); bool bAlmostDead = bNeedHealthBad && ( m_pPlayerInfo->GetHealth() < (CUtil::iPlayerMaxHealth/5) ); bool bNeedWeapon = CMod::HasMapItems(EEntityTypeWeapon), bNeedAmmo = CMod::HasMapItems(EEntityTypeAmmo); TWeaponId iWeapon; bool bSecondary = false; const CEntityClass* pEntityClass = NULL; // Weapon or ammo class to search for. if ( bAlmostDead ) { m_bDontAttack = true; // TODO: try to not to pass to zones with enemy. m_bFlee = true; } int retries = 0; restart_find_task: retries++; if ( retries == 5 ) { m_bNeedTaskCheck = true; DebugAssert(m_iCurrentTask == EBotTaskInvalid); BotMessage("%s -> No task, will continue to look for task on new frame.", GetName()); return; } if ( bNeedHealthBad ) // Need health pretty much. { iNewTask = EBotTaskFindHealth; bForce = true; } else if ( bNeedWeapon && (pWeapon->iBotPreference < iWeaponPreference) ) // Need some weapon with higher preference. { iNewTask = EBotTaskFindWeapon; } else if ( bNeedAmmo ) { // Need ammunition. bool bNeedAmmo0 = (m_aWeapons[m_iBestWeapon].ExtraBullets(0) < pWeapon->iClipSize[0]); // Has less than 1 extra clip. bool bNeedAmmo1 = pWeapon->bHasSecondary && !pWeapon->bSecondaryUseSameBullets && // Has secondary function, but no secondary bullets. !m_aWeapons[m_iBestWeapon].HasAmmoInClip(1) && !m_aWeapons[m_iBestWeapon].HasAmmoExtra(1); if ( bNeedAmmo0 || bNeedAmmo1 ) { iNewTask = EBotTaskFindAmmo; // Prefer search for secondary ammo only if has extra bullets for primary. bSecondary = bNeedAmmo1 && (m_aWeapons[m_iBestWeapon].ExtraBullets(0) > 0); pEntityClass = pWeapon->aAmmos[bSecondary][ rand() % pWeapon->aAmmos[bSecondary].size() ]; } else if ( bNeedHealth ) // Need health (but has more than 50%). iNewTask = EBotTaskFindHealth; else if ( CMod::HasMapItems(EEntityTypeArmor) && (m_pPlayerInfo->GetArmorValue() < CUtil::iPlayerMaxArmor) ) // Need armor. iNewTask = EBotTaskFindArmor; else if ( bNeedWeapon && (pWeapon->iBotPreference < EBotPro) ) // Check if can find a better weapon. { iNewTask = EBotTaskFindWeapon; iWeaponPreference = pWeapon->iBotPreference+1; } else if ( CMod::HasMapItems(EEntityTypeAmmo) && !m_aWeapons[m_iBestWeapon].FullAmmo(1) ) // Check if weapon needs secondary ammo. { iNewTask = EBotTaskFindAmmo; bSecondary = true; } else if ( CMod::HasMapItems(EEntityTypeAmmo) && !m_aWeapons[m_iBestWeapon].FullAmmo(0) ) // Check if weapon needs primary ammo. { iNewTask = EBotTaskFindAmmo; bSecondary = false; } else iNewTask = EBotTaskFindEnemy; } switch(iNewTask) { case EBotTaskFindWeapon: pEntityClass = NULL; // Get weapon entity class to search for. Search for better weapons that actually have. for ( TBotIntelligence iPreference = iWeaponPreference; iPreference < EBotIntelligenceTotal; ++iPreference ) { iWeapon = CWeapons::GetRandomWeapon(iPreference, m_cSkipWeapons); if ( iWeapon != -1 ) { pEntityClass = CWeapons::Get(iWeapon)->pWeaponClass; break; } } if ( pEntityClass == NULL ) { // None found, search for worst weapons. for ( TBotIntelligence iPreference = iWeaponPreference-1; iPreference >= 0; --iPreference ) { iWeapon = CWeapons::GetRandomWeapon(iPreference, m_cSkipWeapons); if ( iWeapon != -1 ) { pEntityClass = CWeapons::Get(iWeapon)->pWeaponClass; break; } } } if ( pEntityClass == NULL ) { bNeedWeapon = false; goto restart_find_task; } break; case EBotTaskFindAmmo: // Get ammo entity class to search for. iWeapon = m_iBestWeapon; // Randomly search for weapon instead, as it gives same primary bullets. if ( !bSecondary && bNeedWeapon && CItems::ExistsOnMap(pWeapon->pWeaponClass) && (rand() & 1) ) { iNewTask = EBotTaskFindWeapon; pEntityClass = pWeapon->pWeaponClass; } else { int iIdx = rand() % pWeapon->aAmmos[bSecondary].size(); pEntityClass = pWeapon->aAmmos[bSecondary][ iIdx ]; // Randomly search for ammo. } if ( !CItems::ExistsOnMap(pEntityClass) ) // There are no such weapon/ammo on the map. { iNewTask = EBotTaskFindEnemy; // Just find enemy. pEntityClass = NULL; } break; case EBotTaskFindHealth: case EBotTaskFindArmor: pEntityClass = CItems::GetRandomItemClass(EEntityTypeHealth + (iNewTask - EBotTaskFindHealth)); break; } DebugAssert( iNewTask != EBotTaskInvalid ); // Check if need task switch. if ( bForce || (m_iCurrentTask != iNewTask) ) { m_iCurrentTask = iNewTask; if ( pEntityClass ) // Health, armor, weapon, ammo. { TEntityType iType = EEntityTypeHealth + (iNewTask - EBotTaskFindHealth); TEntityIndex iItemToSearch = CItems::GetNearestItem( iType, GetHead(), m_aPickedItems, pEntityClass ); if ( iItemToSearch == -1 ) { m_cSkipWeapons.set(iWeapon); m_iCurrentTask = EBotTaskInvalid; goto restart_find_task; } else { m_iTaskDestination = CItems::GetItems(iType)[iItemToSearch].iWaypoint; m_cItemToSearch.iType = iType; m_cItemToSearch.iIndex = iItemToSearch; } } else if (m_iCurrentTask == EBotTaskFindEnemy) { // Just go to some random waypoint. m_iTaskDestination = -1; if ( CWaypoints::Size() >= 2 ) { do { m_iTaskDestination = rand() % CWaypoints::Size(); } while ( m_iTaskDestination == iCurrentWaypoint ); } } // Check if waypoint to go to is valid. if ( (m_iTaskDestination == -1) || (m_iTaskDestination == iCurrentWaypoint) ) { BotMessage( "%s -> task %s, invalid waypoint %d (current %d), recalculate task.", GetName(), CTypeToString::BotTaskToString(m_iCurrentTask).c_str(), m_iTaskDestination, iCurrentWaypoint ); m_iCurrentTask = -1; m_bNeedTaskCheck = true; // Check new task in next frame. m_bNeedMove = m_bUseNavigatorToMove = m_bDestinationChanged = false; // Bot searched for item at current waypoint, but item was not there. Add it to array of picked items. TaskFinished(); } else { BotMessage( "%s -> new task: %s %s, waypoint %d (current %d).", GetName(), CTypeToString::BotTaskToString(m_iCurrentTask).c_str(), pEntityClass ? pEntityClass->sClassName.c_str() : "", m_iTaskDestination, iCurrentWaypoint ); m_iDestinationWaypoint = m_iTaskDestination; m_bNeedMove = m_bUseNavigatorToMove = m_bDestinationChanged = true; } } m_cSkipWeapons.reset(); }