/** ** Attack opponent with force. ** ** @param force Force number to attack with. */ global void AiAttackWithForce(int force) { const AiUnit* aiunit; const Unit* enemy; int x; int y; AiCleanForce(force); AiPlayer->Force[force].Attacking=0; if( (aiunit=AiPlayer->Force[force].Units) ) { AiPlayer->Force[force].Attacking=1; enemy=NoUnitP; while( aiunit && !enemy ) { // Use an unit that can attack if( aiunit->Unit->Type->CanAttack ) { enemy = AttackUnitsInDistance(aiunit->Unit, MaxMapWidth); } aiunit=aiunit->Next; } if (!enemy) { DebugLevel0Fn("Need to plan an attack with transporter\n"); if( !AiPlayer->Force[force].State && !AiPlanAttack(&AiPlayer->Force[force]) ) { DebugLevel0Fn("Can't transport, look for walls\n"); if( !AiFindWall(&AiPlayer->Force[force]) ) { AiPlayer->Force[force].Attacking=0; } } return; } AiPlayer->Force[force].State=0; x = enemy->X; y = enemy->Y; // // Send all units in the force to enemy. // aiunit=AiPlayer->Force[force].Units; while( aiunit ) { if( aiunit->Unit->Type->CanAttack ) { CommandAttack(aiunit->Unit, x, y, NULL,FlushCommands); } else { CommandMove(aiunit->Unit, x, y, FlushCommands); } aiunit=aiunit->Next; } } }
/** ** Force on attack ride. We attack until there is no unit or enemy left. ** ** @param force Force pointer. */ void AiForce::Update() { Assert(Defending == false); if (Size() == 0) { Attacking = false; if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu was destroyed, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } return; } Attacking = false; for (unsigned int i = 0; i < Size(); ++i) { CUnit *aiunit = Units[i]; if (aiunit->Type->CanAttack) { Attacking = true; break; } } if (Attacking == false) { if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu has lost all agresive units, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } return ; } #if 0 if (State == AiForceAttackingState_Waiting) { if (!this->PlanAttack()) { DebugPrint("Can't transport, look for walls\n"); if (!AiFindWall(this)) { Attacking = false; return ; } } State = AiForceAttackingState_Boarding; } #endif if (State == AiForceAttackingState_Boarding) { AiGroupAttackerForTransport(*this); return ; } if (State == AiForceAttackingState_AttackingWithTransporter) { // Move transporters to goalpos std::vector<CUnit *> transporters; bool emptyTrans = true; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.CanMove() && aiunit.Type->MaxOnBoard) { transporters.push_back(&aiunit); if (aiunit.BoardCount > 0) { emptyTrans = false; } } } if (transporters.empty()) { // Our transporters have been destroyed DebugPrint("%d: Attack force #%lu has lost all agresive units, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } else if (emptyTrans) { // We have emptied our transporters, go go go State = AiForceAttackingState_GoingToRallyPoint; } else { for (size_t i = 0; i != transporters.size(); ++i) { CUnit &trans = *transporters[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. trans.Wait = delay; CommandUnload(trans, this->GoalPos, NULL, FlushCommands); } } return; } CUnit *leader = NULL; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.IsAgressive()) { leader = &aiunit; break; } } const int thresholdDist = 5; // Hard coded value Assert(Map.Info.IsPointOnMap(GoalPos)); if (State == AiForceAttackingState_GoingToRallyPoint) { // Check if we are near the goalpos int minDist = Units[0]->MapDistanceTo(this->GoalPos); int maxDist = minDist; for (size_t i = 0; i != Size(); ++i) { const int distance = Units[i]->MapDistanceTo(this->GoalPos); minDist = std::min(minDist, distance); maxDist = std::max(maxDist, distance); } if (WaitOnRallyPoint > 0 && minDist <= thresholdDist) { --WaitOnRallyPoint; } if (maxDist <= thresholdDist || !WaitOnRallyPoint) { const CUnit *unit = NULL; AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &unit); if (!unit) { AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &unit); if (!unit) { // No enemy found, give up // FIXME: should the force go home or keep trying to attack? DebugPrint("%d: Attack force #%lu can't find a target, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Attacking = false; State = AiForceAttackingState_Waiting; return; } } this->GoalPos = unit->tilePos; State = AiForceAttackingState_Attacking; for (size_t i = 0; i != this->Size(); ++i) { CUnit &aiunit = *this->Units[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. aiunit.Wait = delay; if (aiunit.IsAgressive()) { CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands); } else { if (leader) { CommandDefend(aiunit, *leader, FlushCommands); } else { CommandMove(aiunit, this->GoalPos, FlushCommands); } } } } } std::vector<CUnit *> idleUnits; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.IsIdle()) { idleUnits.push_back(&aiunit); } } if (idleUnits.empty()) { return; } if (State == AiForceAttackingState_Attacking && idleUnits.size() == this->Size()) { const CUnit *unit = NULL; bool isNaval = false; for (size_t i = 0; i != this->Units.size(); ++i) { CUnit *const unit = this->Units[i]; if (unit->Type->UnitType == UnitTypeNaval && unit->Type->CanAttack) { isNaval = true; break; } } if (isNaval) { AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &unit); } else { AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &unit); } if (!unit) { // No enemy found, give up // FIXME: should the force go home or keep trying to attack? DebugPrint("%d: Attack force #%lu can't find a target, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Attacking = false; State = AiForceAttackingState_Waiting; return; } else { Vec2i resultPos; NewRallyPoint(unit->tilePos, &resultPos); this->GoalPos = resultPos; this->State = AiForceAttackingState_GoingToRallyPoint; } } for (size_t i = 0; i != idleUnits.size(); ++i) { CUnit &aiunit = *idleUnits[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. aiunit.Wait = delay; if (leader) { if (aiunit.IsAgressive()) { if (State == AiForceAttackingState_Attacking) { CommandAttack(aiunit, leader->tilePos, NULL, FlushCommands); } else { CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands); } } else { CommandDefend(aiunit, *leader, FlushCommands); } } else { if (aiunit.IsAgressive()) { CommandAttack(aiunit, this->GoalPos, NULL, FlushCommands); } else { CommandMove(aiunit, this->GoalPos, FlushCommands); } } } }
/** ** Force on attack ride. We attack until there is no unit or enemy left. ** ** @param force Force pointer. */ void AiForce::Update() { if (Size() == 0) { Attacking = false; if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu was destroyed, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } return; } Attacking = false; for (unsigned int i = 0; i < Size(); ++i) { CUnit *aiunit = Units[i]; if (aiunit->Type->CanAttack) { Attacking = true; break; } } if (Attacking == false) { if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu has lost all agresive units, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Reset(true); } return ; } #if 0 if (State == AiForceAttackingState_Waiting) { if (!this->PlanAttack()) { DebugPrint("Can't transport, look for walls\n"); if (!AiFindWall(this)) { Attacking = false; return ; } } State = AiForceAttackingState_Boarding; } #endif if (State == AiForceAttackingState_Boarding) { AiGroupAttackerForTransport(*this); return ; } Assert(Map.Info.IsPointOnMap(GoalPos)); std::vector<CUnit *> idleUnits; const CUnit *leader = NULL; for (unsigned int i = 0; i != Size(); ++i) { CUnit &aiunit = *Units[i]; if (aiunit.IsIdle()) { if (aiunit.IsAliveOnMap()) { idleUnits.push_back(&aiunit); } } else if (leader == NULL && aiunit.CurrentAction() == UnitActionAttack) { const COrder_Attack &order = *static_cast<COrder_Attack *>(aiunit.CurrentOrder()); if (order.HasGoal() && order.IsValid()) { leader = &aiunit; } } } if (idleUnits.empty()) { return ; } if (leader == NULL) { const int thresholdDist = 5; // Hard coded value int maxDist = 0; for (size_t i = 0; i != idleUnits.size(); ++i) { maxDist = std::max(maxDist, idleUnits[i]->MapDistanceTo(this->GoalPos)); } if (maxDist < thresholdDist) { const CUnit *unit = NULL; AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &unit); if (!unit) { // No enemy found, give up // FIXME: should the force go home or keep trying to attack? DebugPrint("%d: Attack force #%lu can't find a target, giving up\n" _C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0]))); Attacking = false; return; } GoalPos = unit->tilePos; } } const Vec2i pos = leader != NULL ? leader->tilePos : this->GoalPos; for (size_t i = 0; i != idleUnits.size(); ++i) { CUnit &aiunit = *idleUnits[i]; const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference. aiunit.Wait = delay; if (aiunit.Type->CanAttack) { CommandAttack(aiunit, pos, NULL, FlushCommands); } else if (aiunit.Type->CanTransport()) { if (aiunit.BoardCount != 0) { CommandUnload(aiunit, pos, NULL, FlushCommands); } else { // FIXME : Retrieve unit blocked (transport previously full) CommandMove(aiunit, aiunit.Player->StartPos, FlushCommands); this->Remove(aiunit); } } else { CommandMove(aiunit, pos, FlushCommands); } } }