Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixed mismatch between CMobileCAI::IsValidTarget and CGameHelper::Get…
…ClosestEnemyUnit.

Introduced CGameHelper::GetClosestValidTarget, that uses (virtual) call
to CMobileCAI::IsValidTarget to determine whether the target is valid.

This fixes bugs with idle/fighting/patrolling units not attacking nearby
enemies when there are closer enemy units which are invalid targets.

(Due to unit->neutral, noChaseCategory, hasUwWeapons, etc.)
  • Loading branch information
tvo committed Oct 29, 2009
1 parent 6267dd4 commit 810ae78
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 45 deletions.
38 changes: 32 additions & 6 deletions rts/Game/GameHelper.cpp
Expand Up @@ -31,7 +31,7 @@
#include "Sim/Misc/ModInfo.h"
#include "Sim/Projectiles/ExplosionGenerator.h"
#include "Sim/Projectiles/Projectile.h"
#include "Sim/Units/CommandAI/CommandAI.h"
#include "Sim/Units/CommandAI/MobileCAI.h"
#include "Sim/Units/UnitTypes/Factory.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Units/Unit.h"
Expand Down Expand Up @@ -590,6 +590,25 @@ struct Friendly_All_Plus_Enemy_InLos_NOT_SYNCED
}
};

/**
* Delegates filtering to CMobileCAI::IsValidTarget.
*
* This is necessary in CMobileCAI and CAirCAI so they can select the closest
* enemy unit which they consider a valid target.
*
* Without the valid target condition, units don't attack anything if an
* the nearest enemy is an invalid target. (e.g. noChaseCategory)
*/
struct Enemy_InLos_ValidTarget : public Enemy_InLos
{
const CMobileCAI* const cai;
Enemy_InLos_ValidTarget(int at, const CMobileCAI* cai) :
Enemy_InLos(at), cai(cai) {}
bool Unit(const CUnit* u) {
return Enemy_InLos::Unit(u) && cai->IsValidTarget(u);
}
};

}; // end of namespace Filter


Expand Down Expand Up @@ -838,9 +857,9 @@ void CGameHelper::GenerateTargets(const CWeapon *weapon, CUnit* lastTarget,
*/
}

CUnit* CGameHelper::GetClosestUnit(const float3 &pos, float radius)
CUnit* CGameHelper::GetClosestUnit(const float3 &pos, float searchRadius)
{
Query::ClosestUnit_ErrorPos_NOT_SYNCED q(pos, radius);
Query::ClosestUnit_ErrorPos_NOT_SYNCED q(pos, searchRadius);
QueryUnits(Filter::Friendly_All_Plus_Enemy_InLos_NOT_SYNCED(), q);
return q.GetClosestUnit();
}
Expand All @@ -852,18 +871,25 @@ CUnit* CGameHelper::GetClosestEnemyUnit(const float3& pos, float searchRadius, i
return q.GetClosestUnit();
}

CUnit* CGameHelper::GetClosestEnemyUnitNoLosTest(const float3 &pos, float radius,
CUnit* CGameHelper::GetClosestValidTarget(const float3& pos, float searchRadius, int searchAllyteam, const CMobileCAI* cai)
{
Query::ClosestUnit q(pos, searchRadius);
QueryUnits(Filter::Enemy_InLos_ValidTarget(searchAllyteam, cai), q);
return q.GetClosestUnit();
}

CUnit* CGameHelper::GetClosestEnemyUnitNoLosTest(const float3 &pos, float searchRadius,
int searchAllyteam, bool sphere, bool canBeBlind)
{
if (sphere) { // includes target radius

Query::ClosestUnit_InLos q(pos, radius, canBeBlind);
Query::ClosestUnit_InLos q(pos, searchRadius, canBeBlind);
QueryUnits(Filter::Enemy(searchAllyteam), q);
return q.GetClosestUnit();

} else { // cylinder (doesn't include target radius)

Query::ClosestUnit_InLos_Cylinder q(pos, radius, canBeBlind);
Query::ClosestUnit_InLos_Cylinder q(pos, searchRadius, canBeBlind);
QueryUnits(Filter::Enemy(searchAllyteam), q);
return q.GetClosestUnit();

Expand Down
15 changes: 9 additions & 6 deletions rts/Game/GameHelper.h
Expand Up @@ -14,6 +14,7 @@ class CUnit;
class CWeapon;
class CSolidObject;
class CFeature;
class CMobileCAI;

struct UnitDef;
#include "Sim/Misc/DamageArray.h"
Expand All @@ -32,12 +33,14 @@ class CGameHelper
bool TestTrajectoryAllyCone(const float3 &from, const float3& flatdir, float length, float linear, float quadratic, float spread, float baseSize, int allyteam, CUnit* owner);
bool TestTrajectoryNeutralCone(const float3 &from, const float3& flatdir, float length, float linear, float quadratic, float spread, float baseSize, CUnit* owner);

void GetEnemyUnits(const float3& pos,float radius,int searchAllyteam,std::vector<int>& found);
CUnit* GetClosestUnit(const float3& pos,float radius);
CUnit* GetClosestEnemyUnit(const float3& pos,float radius,int searchAllyteam);
CUnit* GetClosestEnemyUnitNoLosTest(const float3& pos,float radius,int searchAllyteam,bool sphere,bool canBeBlind);
CUnit* GetClosestFriendlyUnit(const float3& pos,float radius,int searchAllyteam);
CUnit* GetClosestEnemyAircraft(const float3& pos,float radius,int searchAllyteam);
void GetEnemyUnits(const float3& pos, float searchRadius, int searchAllyteam, std::vector<int>& found);
CUnit* GetClosestUnit(const float3& pos, float searchRadius);
CUnit* GetClosestEnemyUnit(const float3& pos, float searchRadius, int searchAllyteam);
CUnit* GetClosestValidTarget(const float3& pos, float radius, int searchAllyteam, const CMobileCAI* cai);
CUnit* GetClosestEnemyUnitNoLosTest(const float3& pos, float searchRadius, int searchAllyteam, bool sphere, bool canBeBlind);
CUnit* GetClosestFriendlyUnit(const float3& pos, float searchRadius, int searchAllyteam);
CUnit* GetClosestEnemyAircraft(const float3& pos, float searchRadius, int searchAllyteam);

void GenerateTargets(const CWeapon *attacker, CUnit* lastTarget,std::map<float,CUnit*> &targets);
float TraceRay(const float3& start,const float3& dir,float length,float power,const CUnit* owner,const CUnit*& hit,int collisionFlags=0);
float GuiTraceRay(const float3& start,const float3& dir,float length,const CUnit*& hit,bool useRadar,const CUnit* exclude=NULL);
Expand Down
27 changes: 13 additions & 14 deletions rts/Sim/Units/CommandAI/AirCAI.cpp
Expand Up @@ -240,10 +240,10 @@ void CAirCAI::SlowUpdate()
return;
}
}
float testRad = 500 * owner->moveState;
CUnit* enemy = helper->GetClosestEnemyUnit(
owner->pos + (owner->speed * 20), testRad, owner->allyteam);
if(IsValidTarget(enemy)) {
const float searchRadius = 500 * owner->moveState;
CUnit* enemy = helper->GetClosestValidTarget(
owner->pos + (owner->speed * 20), searchRadius, owner->allyteam, this);
if (enemy != NULL) {
Command nc;
nc.id = CMD_ATTACK;
nc.params.push_back(enemy->id);
Expand Down Expand Up @@ -399,13 +399,12 @@ void CAirCAI::ExecuteFight(Command &c)
// CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway...
if (owner->unitDef->canAttack && owner->fireState >= 2
&& owner->moveState != 0 && owner->maxRange > 0) {
float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2,
owner->pos + owner->speed*10);
float testRad = 1000 * owner->moveState;
CUnit* enemy = NULL;
if(myPlane->IsFighter()) {
enemy = helper->GetClosestEnemyAircraft(curPosOnLine,
testRad, owner->allyteam);
const float3 curPosOnLine = ClosestPointOnLine(
commandPos1, commandPos2, owner->pos + owner->speed*10);
const float searchRadius = 1000 * owner->moveState;
enemy = helper->GetClosestEnemyAircraft(curPosOnLine, searchRadius, owner->allyteam);
}
if(IsValidTarget(enemy) && (owner->moveState!=1
|| LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000))
Expand All @@ -423,11 +422,11 @@ void CAirCAI::ExecuteFight(Command &c)
}
return;
} else {
float3 curPosOnLine = ClosestPointOnLine(
commandPos1, commandPos2, owner->pos + owner->speed * 20);
float testRad = 500 * owner->moveState;
enemy = helper->GetClosestEnemyUnit(curPosOnLine, testRad, owner->allyteam);
if(IsValidTarget(enemy)) {
const float3 curPosOnLine = ClosestPointOnLine(
commandPos1, commandPos2, owner->pos + owner->speed * 20);
const float searchRadius = 500 * owner->moveState;
enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this);
if (enemy != NULL) {
Command nc;
nc.id = CMD_ATTACK;
nc.params.push_back(enemy->id);
Expand Down
4 changes: 2 additions & 2 deletions rts/Sim/Units/CommandAI/AirCAI.h
Expand Up @@ -42,12 +42,12 @@ class CAirCAI :
int lastPC1;
int lastPC2;

bool IsValidTarget(const CUnit* enemy) const;

protected:
void PushOrUpdateReturnFight() {
CCommandAI::PushOrUpdateReturnFight(commandPos1, commandPos2);
}

bool IsValidTarget(const CUnit* enemy) const;
};

#endif // __AIR_CAI_H__
28 changes: 13 additions & 15 deletions rts/Sim/Units/CommandAI/MobileCAI.cpp
Expand Up @@ -523,12 +523,11 @@ void CMobileCAI::ExecuteFight(Command &c)
{
assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
if(c.params.size() == 1) {
if(orderTarget && owner->weapons.size() > 0
if(orderTarget && !owner->weapons.empty()
&& !owner->weapons.front()->AttackUnit(orderTarget, false)) {
CUnit* newTarget = helper->GetClosestEnemyUnit(
owner->pos, owner->maxRange, owner->allyteam);
if(IsValidTarget(newTarget) && !owner->weapons.empty()
&& owner->weapons.front()->AttackUnit(newTarget, false)) {
CUnit* newTarget = helper->GetClosestValidTarget(
owner->pos, owner->maxRange, owner->allyteam, this);
if ((newTarget != NULL) && owner->weapons.front()->AttackUnit(newTarget, false)) {
c.params[0] = newTarget->id;
inCommand = false;
} else {
Expand Down Expand Up @@ -575,12 +574,11 @@ void CMobileCAI::ExecuteFight(Command &c)
SetGoal(pos, owner->pos);
}

if(owner->unitDef->canAttack && owner->fireState>=2){
float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
CUnit* enemy=helper->GetClosestEnemyUnit(
curPosOnLine, owner->maxRange + 100 * owner->moveState * owner->moveState,
owner->allyteam);
if(IsValidTarget(enemy) && !owner->weapons.empty()) {
if (owner->unitDef->canAttack && owner->fireState >= 2 && !owner->weapons.empty()) {
const float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos);
const float searchRadius = owner->maxRange + 100 * owner->moveState * owner->moveState;
CUnit* enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this);
if (enemy != NULL) {
Command c2;
c2.id=CMD_FIGHT;
c2.options=c.options|INTERNAL_ORDER;
Expand Down Expand Up @@ -1112,13 +1110,13 @@ void CMobileCAI::IdleCheck(void)
&& owner->moveState && owner->fireState>=2 &&
!owner->weapons.empty() && !owner->haveTarget)
{
CUnit* u = helper->GetClosestEnemyUnit(owner->pos,
owner->maxRange + 150 * owner->moveState * owner->moveState, owner->allyteam);
if(IsValidTarget(u)) {
const float searchRadius = owner->maxRange + 150 * owner->moveState * owner->moveState;
CUnit* enemy = helper->GetClosestValidTarget(owner->pos, searchRadius, owner->allyteam, this);
if (enemy != NULL) {
Command c;
c.id=CMD_ATTACK;
c.options=INTERNAL_ORDER;
c.params.push_back(u->id);
c.params.push_back(enemy->id);
c.timeOut=gs->frameNum+140;
commandQue.push_front(c);
return;
Expand Down
4 changes: 2 additions & 2 deletions rts/Sim/Units/CommandAI/MobileCAI.h
Expand Up @@ -64,6 +64,8 @@ class CMobileCAI :

int GetCancelDistance() { return cancelDistance; }

virtual bool IsValidTarget(const CUnit* enemy) const;

protected:
int cancelDistance;
int lastCloseInTry;
Expand All @@ -74,8 +76,6 @@ class CMobileCAI :
CCommandAI::PushOrUpdateReturnFight(commandPos1, commandPos2);
}

virtual bool IsValidTarget(const CUnit* enemy) const;

void CalculateCancelDistance();
};

Expand Down

0 comments on commit 810ae78

Please sign in to comment.