[-] Transporters don't attack inagressive air units

This commit is contained in:
cybermind 2015-02-26 17:50:55 +05:00
parent 7c28912489
commit 7cb2a8f9a4
8 changed files with 92 additions and 46 deletions

View file

@ -55,6 +55,7 @@
#define AIATTACK_RANGE 0
#define AIATTACK_ALLMAP 1
#define AIATTACK_BUILDING 2
#define AIATTACK_AGRESSIVE 3
template <const int FIND_TYPE>
class AiForceEnemyFinder
@ -86,11 +87,17 @@ public:
} else if (FIND_TYPE == AIATTACK_ALLMAP) {
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth);
} else if (FIND_TYPE == AIATTACK_BUILDING) {
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth, true);
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth, IsBuildingType());
Assert(!*enemy || (*enemy)->Type->Building);
if (*enemy == NULL) {
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth);
}
} else if (FIND_TYPE == AIATTACK_AGRESSIVE) {
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth, IsAggresiveUnit());
Assert(!*enemy || (*enemy)->IsAgressive());
if (*enemy == NULL) {
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth);
}
}
return *enemy == NULL;
}
@ -386,10 +393,20 @@ void AiForce::Attack(const Vec2i &pos)
break;
}
}
bool isTransporter = false;
for (size_t i = 0; i != this->Units.size(); ++i) {
CUnit *const unit = this->Units[i];
if (unit->Type->CanTransport() && unit->IsAgressive() == false) {
isTransporter = true;
break;
}
}
if (Map.Info.IsPointOnMap(goalPos) == false) {
/* Search in entire map */
const CUnit *enemy = NULL;
if (isNaval) {
if (isTransporter) {
AiForceEnemyFinder<AIATTACK_AGRESSIVE>(*this, &enemy);
} else if (isNaval) {
AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &enemy);
} else {
AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &enemy);
@ -400,7 +417,7 @@ void AiForce::Attack(const Vec2i &pos)
} else {
isDefenceForce = true;
}
if (Map.Info.IsPointOnMap(goalPos) == false) {
if (Map.Info.IsPointOnMap(goalPos) == false || isTransporter) {
DebugPrint("%d: Need to plan an attack with transporter\n" _C_ AiPlayer->Player->Index);
if (State == AiForceAttackingState_Waiting && !PlanAttack()) {
DebugPrint("%d: Can't transport\n" _C_ AiPlayer->Player->Index);

View file

@ -75,6 +75,9 @@ public:
|| unit->CurrentAction() == UnitActionDie) {
return;
}
if (unit->Type->UnitType == UnitTypeFly && unit->IsAgressive() == false) {
return;
}
if (pos.x < unit->tilePos.x || pos.x >= unit->tilePos.x + type.TileWidth
|| pos.y < unit->tilePos.y || pos.y >= unit->tilePos.y + type.TileHeight) {
return;

View file

@ -442,7 +442,7 @@ public:
bool GrayscaleIcons; /// Use grayscaled icons for unavailable units, upgrades, etc
bool IconsShift; /// Shift icons slightly when you press on them
bool StereoSound; /// Enables/diables stereo sound effects
bool MineNotifications; /// Show mine is running low/depleted messages (as in Warcraft 3)
bool MineNotifications; /// Show mine is running low/depleted messages
int ShowOrders; /// How many second show orders of unit on map.
int ShowNameDelay; /// How many cycles need to wait until unit's name popup will appear.

View file

@ -45,7 +45,19 @@
// Some predicates
//
class HasSameTypeAs
class CUnitFilter
{
public:
bool operator()(const CUnit *unit) const { return true; };
};
class NoFilter : public CUnitFilter
{
public:
bool operator()(const CUnit *) const { return true; }
};
class HasSameTypeAs : public CUnitFilter
{
public:
explicit HasSameTypeAs(const CUnitType &_type) : type(&_type) {}
@ -54,7 +66,7 @@ private:
const CUnitType *type;
};
class HasSamePlayerAs
class HasSamePlayerAs : public CUnitFilter
{
public:
explicit HasSamePlayerAs(const CPlayer &_player) : player(&_player) {}
@ -63,7 +75,7 @@ private:
const CPlayer *player;
};
class HasNotSamePlayerAs
class HasNotSamePlayerAs : public CUnitFilter
{
public:
explicit HasNotSamePlayerAs(const CPlayer &_player) : player(&_player) {}
@ -72,7 +84,7 @@ private:
const CPlayer *player;
};
class IsAlliedWith
class IsAlliedWith : public CUnitFilter
{
public:
explicit IsAlliedWith(const CPlayer &_player) : player(&_player) {}
@ -81,7 +93,7 @@ private:
const CPlayer *player;
};
class IsEnemyWith
class IsEnemyWith : public CUnitFilter
{
public:
explicit IsEnemyWith(const CPlayer &_player) : player(&_player) {}
@ -90,7 +102,7 @@ private:
const CPlayer *player;
};
class HasSamePlayerAndTypeAs
class HasSamePlayerAndTypeAs : public CUnitFilter
{
public:
explicit HasSamePlayerAndTypeAs(const CUnit &unit) :
@ -110,7 +122,7 @@ private:
const CUnitType *type;
};
class IsNotTheSameUnitAs
class IsNotTheSameUnitAs : public CUnitFilter
{
public:
explicit IsNotTheSameUnitAs(const CUnit &unit) : forbidden(&unit) {}
@ -119,13 +131,19 @@ private:
const CUnit *forbidden;
};
class IsBuildingType
class IsBuildingType : public CUnitFilter
{
public:
bool operator()(const CUnit *unit) const { return unit->Type->Building; }
};
class OutOfMinRange
class IsAggresiveUnit : public CUnitFilter
{
public:
bool operator()(const CUnit *unit) const { return unit->IsAgressive(); }
};
class OutOfMinRange : public CUnitFilter
{
public:
explicit OutOfMinRange(const int range, const Vec2i pos) : range(range), pos(pos) {}
@ -137,7 +155,7 @@ private:
template <typename Pred>
class NotPredicate
class NotPredicate : public CUnitFilter
{
public:
explicit NotPredicate(Pred _pred) : pred(_pred) {}
@ -150,7 +168,7 @@ template <typename Pred>
NotPredicate<Pred> MakeNotPredicate(Pred pred) { return NotPredicate<Pred>(pred); }
template <typename Pred1, typename Pred2>
class AndPredicate
class AndPredicate : public CUnitFilter
{
public:
AndPredicate(Pred1 _pred1, Pred2 _pred2) : pred1(_pred1), pred2(_pred2) {}
@ -310,12 +328,17 @@ extern CUnit *ResourceDepositOnMap(const Vec2i &pos, int resource);
/// Check map for obstacles in a line between 2 tiles
extern bool CheckObstaclesBetweenTiles(const Vec2i &unitPos, const Vec2i &goalPos, unsigned short flags, int *distance = NULL);
/// Find best enemy in numeric range to attack
extern CUnit *AttackUnitsInDistance(const CUnit &unit, int range, bool onlyBuildings = false);
extern CUnit *AttackUnitsInDistance(const CUnit &unit, int range, CUnitFilter pred);
extern CUnit *AttackUnitsInDistance(const CUnit &unit, int range);
/// Find best enemy in attack range to attack
extern CUnit *AttackUnitsInRange(const CUnit &unit, CUnitFilter pred);
extern CUnit *AttackUnitsInRange(const CUnit &unit);
/// Find best enemy in reaction range to attack
extern CUnit *AttackUnitsInReactRange(const CUnit &unit, CUnitFilter pred);
extern CUnit *AttackUnitsInReactRange(const CUnit &unit);
//@}
#endif // !__UNIT_FIND_H__

View file

@ -543,9 +543,9 @@ static int CostMoveToCallBack_Default(unsigned int index, const CUnit &unit)
} else {
// for non moving unit Always Fail unless goal is unit, or unit can attack the target
if (&unit != goal) {
if (goal->Player->IsEnemy(unit) && unit.IsAgressive() && CanTarget(*unit.Type, *goal->Type)
&& goal->Variable[UNHOLYARMOR_INDEX].Value == 0 && goal->IsVisibleAsGoal(*unit.Player)) {
cost += 2 * AStarMovingUnitCrossingCost;
if (goal->Player->IsEnemy(unit) && unit.IsAgressive() && CanTarget(*unit.Type, *goal->Type)
&& goal->Variable[UNHOLYARMOR_INDEX].Value == 0 && goal->IsVisibleAsGoal(*unit.Player)) {
cost += 2 * AStarMovingUnitCrossingCost;
} else {
// FIXME: Need support for moving a fixed unit to add cost
return -1;

View file

@ -210,7 +210,7 @@ extern void beos_init(int argc, char **argv);
#ifdef USE_STACKTRACE
#include <stdexcept>
#include <stacktrace/call_stack.hpp>
#include <stacktrace/call_stack.hpp>
#include <stacktrace/stack_exception.hpp>
#endif

View file

@ -43,7 +43,7 @@
#ifdef USE_STACKTRACE
#include <stdexcept>
#include <stacktrace/call_stack.hpp>
#include <stacktrace/call_stack.hpp>
#include <stacktrace/stack_exception.hpp>
#endif

View file

@ -54,12 +54,6 @@
-- Finding units
----------------------------------------------------------------------------*/
class NoFilter
{
public:
bool operator()(const CUnit *) const { return true; }
};
void Select(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &units)
{
Select(ltPos, rbPos, units, NoFilter());
@ -740,6 +734,10 @@ private:
return INT_MAX;
}
if (dtype.UnitType == UnitTypeFly && dest->IsAgressive() == false) {
return INT_MAX;
}
// Calculate the costs to attack the unit.
// Unit with the smallest attack costs will be taken.
int cost = 0;
@ -1123,7 +1121,7 @@ bool CheckObstaclesBetweenTiles(const Vec2i &unitPos, const Vec2i &goalPos, unsi
**
** @return Unit to be attacked.
*/
CUnit *AttackUnitsInDistance(const CUnit &unit, int range, bool onlyBuildings)
CUnit *AttackUnitsInDistance(const CUnit &unit, int range, CUnitFilter pred)
{
// if necessary, take possible damage on allied units into account...
if (unit.Type->Missile.Missile->Range > 1
@ -1138,13 +1136,8 @@ CUnit *AttackUnitsInDistance(const CUnit &unit, int range, bool onlyBuildings)
// If unit is removed, use containers x and y
const CUnit *firstContainer = unit.Container ? unit.Container : &unit;
std::vector<CUnit *> table;
if (onlyBuildings) {
SelectAroundUnit(*firstContainer, missile_range, table,
MakeAndPredicate(HasNotSamePlayerAs(Players[PlayerNumNeutral]), IsBuildingType()));
} else {
SelectAroundUnit(*firstContainer, missile_range, table,
MakeNotPredicate(HasSamePlayerAs(Players[PlayerNumNeutral])));
}
SelectAroundUnit(*firstContainer, missile_range, table,
MakeAndPredicate(HasNotSamePlayerAs(Players[PlayerNumNeutral]), pred));
if (table.empty() == false) {
return BestRangeTargetFinder(unit, range).Find(table);
@ -1155,13 +1148,8 @@ CUnit *AttackUnitsInDistance(const CUnit &unit, int range, bool onlyBuildings)
const CUnit *firstContainer = unit.Container ? unit.Container : &unit;
std::vector<CUnit *> table;
if (onlyBuildings) {
SelectAroundUnit(*firstContainer, range, table,
MakeAndPredicate(HasNotSamePlayerAs(Players[PlayerNumNeutral]), IsBuildingType()));
} else {
SelectAroundUnit(*firstContainer, range, table,
MakeNotPredicate(HasSamePlayerAs(Players[PlayerNumNeutral])));
}
SelectAroundUnit(*firstContainer, range, table,
MakeAndPredicate(HasNotSamePlayerAs(Players[PlayerNumNeutral]), pred));
const int n = static_cast<int>(table.size());
if (range > 25 && table.size() > 9) {
@ -1173,6 +1161,11 @@ CUnit *AttackUnitsInDistance(const CUnit &unit, int range, bool onlyBuildings)
}
}
CUnit *AttackUnitsInDistance(const CUnit &unit, int range)
{
return AttackUnitsInDistance(unit, range, NoFilter());
}
/**
** Attack units in attack range.
**
@ -1180,10 +1173,15 @@ CUnit *AttackUnitsInDistance(const CUnit &unit, int range, bool onlyBuildings)
**
** @return Pointer to unit which should be attacked.
*/
CUnit *AttackUnitsInRange(const CUnit &unit)
CUnit *AttackUnitsInRange(const CUnit &unit, CUnitFilter pred)
{
Assert(unit.Type->CanAttack);
return AttackUnitsInDistance(unit, unit.Stats->Variables[ATTACKRANGE_INDEX].Max);
return AttackUnitsInDistance(unit, unit.Stats->Variables[ATTACKRANGE_INDEX].Max, pred);
}
CUnit *AttackUnitsInRange(const CUnit &unit)
{
return AttackUnitsInRange(unit, NoFilter());
}
/**
@ -1193,11 +1191,16 @@ CUnit *AttackUnitsInRange(const CUnit &unit)
**
** @return Pointer to unit which should be attacked.
*/
CUnit *AttackUnitsInReactRange(const CUnit &unit)
CUnit *AttackUnitsInReactRange(const CUnit &unit, CUnitFilter pred)
{
Assert(unit.Type->CanAttack);
const int range = unit.Player->Type == PlayerPerson ? unit.Type->ReactRangePerson : unit.Type->ReactRangeComputer;
return AttackUnitsInDistance(unit, range);
return AttackUnitsInDistance(unit, range, pred);
}
CUnit *AttackUnitsInReactRange(const CUnit &unit)
{
return AttackUnitsInReactRange(unit, NoFilter());
}
//@}