1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
#include "Attack.h"
#include "../CGroup.h"
#include "../CUnitTable.h"
#include "../CDefenseMatrix.h"
#include "../CPathfinder.h"
AttackTask::AttackTask(AIClasses *_ai, int target, CGroup &group): ATask(_ai) {
const UnitDef *eud = ai->cbc->GetUnitDef(target);
this->t = TASK_ATTACK;
this->target = target;
this->pos = ai->cbc->GetUnitPos(target);
if (eud)
this->enemy = eud->humanName;
targetAlt = -1;
addGroup(group);
}
bool AttackTask::onValidate() {
CGroup *group = firstGroup();
if (targetAlt >= 0) {
if (ai->cbc->IsUnitCloaked(targetAlt) || !group->canAttack(targetAlt)) {
group->stop();
}
}
const UnitDef *eud = ai->cbc->GetUnitDef(target);
if (eud == NULL)
return false;
if (!isMoving) {
if (ai->cbc->IsUnitCloaked(target))
return false;
return true;
}
if (!group->canAttack(target))
return false;
// don't chase scout groups too long if they are out of base...
bool scoutGroup = (group->cats&SCOUTER).any();
if (!scoutGroup && lifeTime() > 20.0f) {
const unitCategory ecats = UC(eud->id);
if ((ecats&SCOUTER).any() && !ai->defensematrix->isPosInBounds(pos))
return false;
}
float targetDistance = pos.distance2D(group->pos());
if (targetDistance > 1000.0f)
return true; // too far to panic
if (ai->cbc->IsUnitCloaked(target))
return false;
bool isBaseThreat = ai->defensematrix->isPosInBounds(pos);
// if there is no threat to our base then prevent useless attack for groups
// which are not too cheap
if (!isBaseThreat && (group->costMetal / group->units.size()) >= 100.0f) {
float threatRange;
if (scoutGroup)
threatRange = 300.0f;
else
threatRange = 0.0f;
if (group->getThreat(pos, threatRange) > group->strength)
return false;
}
return true;
}
void AttackTask::onUpdate() {
CGroup *group = firstGroup();
if (group->isMicroing() && group->isIdle()) {
targetAlt = -1; // for sure
group->micro(false);
}
if (isMoving) {
/* Keep tracking the target */
pos = ai->cbc->GetUnitPos(target);
float3 gpos = group->pos();
float dist = gpos.distance2D(pos);
float range = group->getRange();
/* See if we can attack our target already */
if (dist <= range) {
bool canAttack = true;
/*
// for ground units prevent shooting across hill...
if ((group->cats&AIR).none()) {
// FIXME: improve
dist = ai->pathfinder->getPathLength(*group, pos);
canAttack = (dist <= range * 1.1f);
}
*/
if (canAttack) {
if ((group->cats&BUILDER).any())
group->reclaim(target);
else
group->attack(target);
isMoving = false;
ai->pathfinder->remove(*group);
group->micro(true);
}
}
}
/* See if we can attack a target we found on our path */
if (!(group->isMicroing() || urgent())) {
if ((group->cats&BUILDER).any())
resourceScan(); // builders should not be too aggressive
else
enemyScan(targetAlt);
}
}
void AttackTask::toStream(std::ostream& out) const {
out << "AttackTask(" << key << ") target(" << enemy << ") ";
CGroup *group = firstGroup();
if (group)
out << (*group);
}
void AttackTask::onEnemyDestroyed(int enemy, int attacker) {
if (target == enemy) {
LOG_II("AttackTask::onEnemyDestroyed")
remove();
}
}
|