bool MeleeCombatTask::Perform(Subsystem& subsystem) { DM_LOG(LC_AI, LT_INFO)LOGSTRING("Melee Combat Task performing.\r"); idAI* ownerEnt = _owner.GetEntity(); assert(ownerEnt != NULL); idActor* enemy = _enemy.GetEntity(); if ( ( enemy == NULL ) || enemy->IsKnockedOut() || ( enemy->health <= 0 ) ) { DM_LOG(LC_AI, LT_DEBUG)LOGSTRING("No enemy, terminating task!\r"); return true; // terminate me } // Perform the task according to the current action EMeleeActState actState = ownerEnt->m_MeleeStatus.m_ActionState; switch (actState) { case MELEEACTION_READY: PerformReady(ownerEnt); break; case MELEEACTION_ATTACK: PerformAttack(ownerEnt); break; case MELEEACTION_PARRY: PerformParry(ownerEnt); break; default: PerformReady(ownerEnt); }; return false; // not finished yet }
void AZombieShooterCharacter::Tick(float DeltaSeconds) { Super::Tick(DeltaSeconds); CalculateFacing(); // Determine if the character should perform an attack AttackCooldownRemaining -= DeltaSeconds; if (bAttacking){ PerformAttack(); } }
void AMonsterAIController::PhysicalAttackPriority(ACombatController* &Con) { int32 RandomInt = 0; // First Things First. If the warrior has an ability that is a Self-Buff, he uses it. if (MyMonster->AI_Archetype == EAIArchetypes::Warrior) { CastSelfBuff(Con); if (bHasActionBeenDecidedYet)return; } // If not, then we proceed to check our HP. if ((MyMonster->MaxHealth - MyMonster->CurrentHealth / MyMonster->MaxHealth) >= 0.75f) { // If our HP is low, we check all our enemies that are not currently defending, and are also low on hp to perform an attack of opportunity. TArray<int32> IndexesOfPossibleVictims; for (size_t i = 0; i < 3; i++) { if (!Con->PartyA[i]->bIsDead) { if (Con->PartyA[i]->bIsDefending) { if ((Con->PartyA[i]->MaxHealth - Con->PartyA[i]->CurrentHealth / Con->PartyA[i]->MaxHealth) >= 0.9f) { //Even if they defend, if they have less than 10%, we may have a chance. IndexesOfPossibleVictims.Add(Con->PartyA[i]->MonsterID); } } else { if ((Con->PartyA[i]->MaxHealth - Con->PartyA[i]->CurrentHealth / Con->PartyA[i]->MaxHealth) >= 0.8f) { IndexesOfPossibleVictims.Add(Con->PartyA[i]->MonsterID); } } } } //Prioritize the enemies based on: if (IndexesOfPossibleVictims.Num() > 0) { RandomInt = FMath::FRandRange(1, 100); if (RandomInt <= 40) // Lowest Quantitative Health. { int32 LowLimHP = Con->PartyA[IndexesOfPossibleVictims[0]]->CurrentHealth; int32 IndexOfFinalTarget = 0; for (size_t i = 0; i < IndexesOfPossibleVictims.Num(); i++) { for (size_t j = 0; j < Con->PartyA.Num(); j++) { if (Con->PartyA[j]->MonsterID == IndexesOfPossibleVictims[i]) { if (Con->PartyA[j]->CurrentHealth < LowLimHP) { LowLimHP = Con->PartyA[j]->CurrentHealth; IndexOfFinalTarget = IndexesOfPossibleVictims[i]; } } } } PerformAttack(Con, IndexOfFinalTarget); if (bHasActionBeenDecidedYet)return; } else if (RandomInt <= 75) // Lowest Defense { int32 LowLimDEF = Con->PartyA[IndexesOfPossibleVictims[0]]->GetDefense(); int32 IndexOfFinalTarget = 0; for (size_t i = 0; i < IndexesOfPossibleVictims.Num(); i++) { for (size_t j = 0; j < Con->PartyA.Num(); j++) { if (Con->PartyA[j]->MonsterID == IndexesOfPossibleVictims[i]) { if (Con->PartyA[j]->GetDefense() < LowLimDEF) { LowLimDEF = Con->PartyA[j]->GetDefense(); IndexOfFinalTarget = IndexesOfPossibleVictims[i]; } } } } PerformAttack(Con, IndexOfFinalTarget); if (bHasActionBeenDecidedYet)return; } else // Random. { PerformAttack(Con, IndexesOfPossibleVictims[FMath::RandRange(0, IndexesOfPossibleVictims.Num() - 1)]); if (bHasActionBeenDecidedYet)return; } } else { // No monsters selected. Defend instead. PerformDefend(Con); if (bHasActionBeenDecidedYet)return; } } else { // If our HP is NOT low, we attack based on the prioritization made above. RandomInt = FMath::FRandRange(1, 100); if (RandomInt < 80 || MyMonster->AI_Archetype != EAIArchetypes::Warrior) { TArray<int32> IndexesOfPossibleVictims; for (size_t i = 0; i < 3; i++) { if (!Con->PartyA[i]->bIsDead) { if (Con->PartyA[i]->bIsDefending) { if ((Con->PartyA[i]->MaxHealth - Con->PartyA[i]->CurrentHealth / Con->PartyA[i]->MaxHealth) >= 0.8f) { //Even if they defend, if they have less than 10%, we may have a chance. IndexesOfPossibleVictims.Add(Con->PartyA[i]->MonsterID); } } else { IndexesOfPossibleVictims.Add(Con->PartyA[i]->MonsterID); } } } //Prioritize the enemies based on: if (IndexesOfPossibleVictims.Num() > 0) { RandomInt = FMath::FRandRange(1, 100); if (RandomInt <= 40) // Lowest Quantitative Health. { int32 LowLimHP = Con->PartyA[IndexesOfPossibleVictims[0]]->CurrentHealth; int32 IndexOfFinalTarget = 0; for (size_t i = 0; i < IndexesOfPossibleVictims.Num(); i++) { for (size_t j = 0; j < Con->PartyA.Num(); j++) { if (Con->PartyA[j]->MonsterID == IndexesOfPossibleVictims[i]) { if (Con->PartyA[j]->CurrentHealth < LowLimHP) { LowLimHP = Con->PartyA[j]->CurrentHealth; IndexOfFinalTarget = IndexesOfPossibleVictims[i]; } } } } PerformAttack(Con, IndexOfFinalTarget); if (bHasActionBeenDecidedYet)return; } else if (RandomInt <= 75) // Lowest Defense { int32 LowLimDEF = Con->PartyA[IndexesOfPossibleVictims[0]]->GetDefense(); int32 IndexOfFinalTarget = 0; for (size_t i = 0; i < IndexesOfPossibleVictims.Num(); i++) { for (size_t j = 0; j < Con->PartyA.Num(); j++) { if (Con->PartyA[j]->MonsterID == IndexesOfPossibleVictims[i]) { if (Con->PartyA[j]->GetDefense() < LowLimDEF) { LowLimDEF = Con->PartyA[j]->GetDefense(); IndexOfFinalTarget = IndexesOfPossibleVictims[i]; } } } } PerformAttack(Con, IndexOfFinalTarget); if (bHasActionBeenDecidedYet)return; } else // Random. { PerformAttack(Con, IndexesOfPossibleVictims[FMath::RandRange(0, IndexesOfPossibleVictims.Num() - 1)]); if (bHasActionBeenDecidedYet)return; } } else { // No monsters selected. Defend instead. PerformDefend(Con); if (bHasActionBeenDecidedYet)return; } } else { DecideForSpellToCast(Con); if (bHasActionBeenDecidedYet)return; } } }