Rev.8022 fixed a warning, but broke the behavior of some method.

Here is the fix for these methods.
This commit is contained in:
joris 2012-02-16 14:59:44 +01:00
parent 96dc321b38
commit 0e54eae28e
6 changed files with 339 additions and 400 deletions

View file

@ -50,40 +50,43 @@
----------------------------------------------------------------------------*/
template <const bool IN_REACT_RANGE>
struct AiForceEnemyFinder {
const CUnit *enemy;
inline bool found() const
{
return enemy != NULL;
}
inline bool operator() (const CUnit *const unit)
{
if (IN_REACT_RANGE) {
if (unit->Type->CanAttack) {
enemy = AttackUnitsInReactRange(*unit);
}
} else {
if (unit->Type->CanAttack) {
enemy = AttackUnitsInDistance(*unit, MaxMapWidth);
}
}
return enemy == NULL;
}
AiForceEnemyFinder(int force) : enemy(NULL)
class AiForceEnemyFinder
{
public:
AiForceEnemyFinder(int force, const CUnit** enemy) : enemy(enemy)
{
Assert(enemy != NULL);
*enemy = NULL;
AiPlayer->Force[force].Units.for_each_if(*this);
}
AiForceEnemyFinder(AiForce *force) : enemy(NULL)
AiForceEnemyFinder(AiForce &force, const CUnit** enemy) : enemy(enemy)
{
force->Units.for_each_if(*this);
Assert(enemy != NULL);
*enemy = NULL;
force.Units.for_each_if(*this);
}
bool found() const { return *enemy != NULL; }
bool operator() (const CUnit *const unit) const
{
if (unit->Type->CanAttack == false) {
return *enemy == NULL;
}
if (IN_REACT_RANGE) {
*enemy = AttackUnitsInReactRange(*unit);
} else {
*enemy = AttackUnitsInDistance(*unit, MaxMapWidth);
}
return *enemy == NULL;
}
private:
const CUnit **enemy;
};
class AiForceAttackSender {
class AiForceAttackSender
{
public:
// Send all units in the force to enemy at pos.
AiForceAttackSender(int force, const Vec2i &pos) : goalPos(pos), delta(0)
@ -106,7 +109,7 @@ public:
force->Units.for_each(*this);
}
void operator() (CUnit *const unit)
void operator() (CUnit *const unit) const
{
// this may be problem if units are in bunker and we want sent
// them to attack
@ -126,7 +129,7 @@ public:
private:
Vec2i goalPos;
int delta;
mutable int delta;
};
@ -246,7 +249,7 @@ public:
memset(data, 0, len);
units.for_each(*this);
}
inline void operator() (CUnit *const unit) {
inline void operator() (const CUnit *const unit) const {
data[UnitTypeEquivs[unit->Type->Slot]]++;
}
private:
@ -324,7 +327,8 @@ void AiForce::Attack(const Vec2i &pos)
if (goalPos.x == -1 || goalPos.y == -1) {
/* Search in entire map */
const CUnit *enemy = AiForceEnemyFinder<false>(this).enemy;
const CUnit *enemy = NULL;
AiForceEnemyFinder<false>(*this, &enemy);
if (enemy) {
goalPos = enemy->tilePos;
}
@ -733,7 +737,7 @@ void AiForce::Update()
Vec2i pos;
if (State == AiForceAttackingState_Attacking) {
unit = AiForceEnemyFinder<false>(this).enemy;
AiForceEnemyFinder<false>(*this, &unit);
if (!unit) {
// No enemy found, give up
@ -761,7 +765,8 @@ void AiForceManager::Update()
if (force.Defending) {
force.Clean();
// Look if still enemies in attack range.
if(!AiForceEnemyFinder<true>(&force).found()) {
const CUnit *dummy = NULL;
if(!AiForceEnemyFinder<true>(force, &dummy).found()) {
DebugPrint("%d:FIXME: not written, should send force #%d home\n"
_C_ AiPlayer->Player->Index _C_ f);
force.Defending = false;

View file

@ -53,40 +53,45 @@
-- Functions
----------------------------------------------------------------------------*/
struct _EnemyOnMapTile {
CUnit *best;
const CUnit *const source;
const Vec2i pos;
_EnemyOnMapTile(const CUnit &unit, const Vec2i _pos) : best(0), source(&unit) , pos(_pos) {}
inline void operator() (CUnit *const unit) {
const CUnitType *const type = unit->Type;
class _EnemyOnMapTile
{
public:
_EnemyOnMapTile(const CUnit &unit, const Vec2i _pos, CUnit **enemy) :
source(&unit) , pos(_pos), best(enemy)
{
}
void operator() (CUnit *const unit) const {
const CUnitType &type = *unit->Type;
// unusable unit ?
// if (unit->IsUnusable()) can't attack constructions
// FIXME: did SelectUnitsOnTile already filter this?
// Invisible and not Visible
if (unit->Removed || unit->Variable[INVISIBLE_INDEX].Value ||
//(!UnitVisible(unit, source->Player)) ||
unit->CurrentAction() == UnitActionDie) {
if (unit->Removed || unit->Variable[INVISIBLE_INDEX].Value
// || (!UnitVisible(unit, source->Player))
|| unit->CurrentAction() == UnitActionDie) {
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) {
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;
}
if (!CanTarget(source->Type, type)) {
if (!CanTarget(source->Type, &type)) {
return;
}
if (!source->Player->IsEnemy(*unit)) { // a friend or neutral
return;
}
//
// Choose the best target.
//
if (!best || best->Type->Priority < type->Priority) {
best = unit;
if (!*best || (*best)->Type->Priority < type.Priority) {
*best = unit;
}
return;
}
private:
const CUnit *const source;
const Vec2i pos;
CUnit **best;
};
/**
@ -99,9 +104,11 @@ struct _EnemyOnMapTile {
*/
static CUnit *EnemyOnMapTile(const CUnit &source, const Vec2i& pos)
{
_EnemyOnMapTile filter(source, pos);
CUnit* enemy = NULL;
_EnemyOnMapTile filter(source, pos, &enemy);
Map.Field(pos)->UnitCache.for_each(filter);
return filter.best;
return enemy;
}
/**

View file

@ -44,83 +44,52 @@
----------------------------------------------------------------------------*/
class CUnit;
class CMap;
/**
** Unit cache
*/
struct CUnitCache {
std::vector<CUnit *> Units;
class CUnitCache
{
public:
typedef std::vector<CUnit *>::iterator iterator;
typedef std::vector<CUnit *>::const_iterator const_iterator;
CUnitCache() : Units() { Units.clear();}
public:
CUnitCache() : Units()
{
}
inline size_t size() const
{
return Units.size();
}
inline void clear()
{
Units.clear();
}
inline CUnit * operator[] (const unsigned int index) const
size_t size() const { return Units.size(); }
void clear() { Units.clear(); }
const_iterator begin() const { return Units.begin(); }
iterator begin() { return Units.begin(); }
const_iterator end() const { return Units.end(); }
iterator end() { return Units.end(); }
CUnit * operator[] (const unsigned int index) const
{
//Assert(index < Units.size());
return Units[index];
}
inline CUnit * operator[] (const unsigned int index) {
CUnit * operator[] (const unsigned int index) {
//Assert(index < Units.size());
return Units[index];
}
/**
* @brief Find the first unit in a tile chache for which a predicate is true.
* @brief Find the first unit in a tile cache for which a predicate is true.
* @param pred A predicate object vith bool operator()(const CUnit *).
* @return The first unit i in the cache
* such that @p pred(*i) is true, or NULL if no such iterator exists.
* @return The first unit u in the cache
* such that @p pred(u) is true, or NULL if no such unit exists.
*/
template<typename _T>
inline CUnit *find(const _T &pred) const
CUnit *find(const _T &pred) const
{
#if __GNUC__ < 4
if(Units.size()) {
std::vector<CUnit *>::const_iterator beg(Units.begin()), end(Units.end());
std::vector<CUnit *>::const_iterator ret = std::find_if(beg, end, pred);
return ret != end ? (*ret) : NULL;
}
return NULL;
#else
//GCC version only since std::vector::data() is not in STL
const size_t size = Units.size();
if(size) {
const CUnit *unit;
int n = (size+3)/4;
const CUnit **cache = (const CUnit **)Units.data();
switch (size & 3) {
case 0:
do {
unit = *cache;
if(pred(unit))
return (CUnit *)unit;
cache++;
case 3:
unit = *cache;
if(pred(unit))
return (CUnit *)unit;
cache++;
case 2:
unit = *cache;
if(pred(unit))
return (CUnit *)unit;
cache++;
case 1:
unit = *cache;
if(pred(unit))
return (CUnit *)unit;
cache++;
} while ( --n > 0 );
}
}
return NULL;
#endif
std::vector<CUnit *>::const_iterator ret = std::find_if(Units.begin(), Units.end(), pred);
return ret != Units.end() ? (*ret) : NULL;
}
/**
@ -132,27 +101,13 @@ struct CUnitCache {
* @p functor must not modify the order of the cache.
*/
template<typename _T>
inline void for_each(_T functor)
void for_each(const _T &functor)
{
const size_t size = Units.size();
#if __GNUC__ < 4
for(unsigned int i = 0; i < size; ++i)
for (size_t i = 0; i != size; ++i) {
functor(Units[i]);
#else
//GCC version only since std::vector::data() is not in STL
if(size) {
int n = (size+3)/4;
CUnit **cache = (CUnit **)Units.data();
switch (size & 3) {
case 0: do {
functor(*cache++);
case 3: functor(*cache++);
case 2: functor(*cache++);
case 1: functor(*cache++);
} while ( --n > 0 );
}
}
#endif
}
/**
@ -165,38 +120,16 @@ struct CUnitCache {
* If @p functor return false then loop is exited.
*/
template<typename _T>
inline int for_each_if(_T &functor)
int for_each_if(const _T &functor)
{
const size_t size = Units.size();
size_t count = 0;
#ifdef _MSC_VER
while(size && functor(Units[count]) && ++count < size);
#else
if(size) {
int n = (size+3)/4;
switch (size & 3) {
case 0:
do {
if(!functor(Units[count]))
return count;
count++;
case 3:
if(!functor(Units[count]))
return count;
count++;
case 2:
if(!functor(Units[count]))
return count;
count++;
case 1:
if(!functor(Units[count]))
return count ;
count++;
} while ( --n > 0 );
for (size_t count = 0; count != size; ++count) {
if (functor(Units[count]) == false) {
return count;
}
}
#endif
return count;
return size;
}
@ -206,12 +139,12 @@ struct CUnitCache {
** @param index Unit index to remove from container.
** @return pointer to removed element.
*/
inline CUnit * Remove(const unsigned int index)
CUnit *Remove(const unsigned int index)
{
const size_t size = Units.size();
Assert(index < size);
CUnit *tmp = Units[index];
if(size > 1) {
if (size > 1) {
Units[index] = Units[size - 1];
}
Units.pop_back();
@ -223,15 +156,15 @@ struct CUnitCache {
**
** @param unit Unit pointer to remove from container.
*/
inline bool Remove(CUnit *const unit)
bool Remove(CUnit *const unit)
{
#ifndef SECURE_UNIT_REMOVING
const size_t size = Units.size();
if(size == 1 && unit == Units[0]) {
if (size == 1 && unit == Units[0]) {
Units.pop_back();
return true;
} else {
for(unsigned int i = 0; i < size; ++i) {
for (unsigned int i = 0; i < size; ++i) {
// Do we care on unit sequence in tile cache ?
if (Units[i] == unit) {
Units[i] = Units[size - 1];
@ -241,8 +174,7 @@ struct CUnitCache {
}
}
#else
for(std::vector<CUnit *>::iterator i(Units.begin()), end(Units.end());
i != end; ++i) {
for (std::vector<CUnit *>::iterator i(Units.begin()), end(Units.end()); i != end; ++i) {
if ((*i) == unit) {
Units.erase(i);
return true;
@ -257,10 +189,9 @@ struct CUnitCache {
**
** @param unit Unit pointer to remove from container.
*/
inline void RemoveS(CUnit *const unit)
void RemoveS(CUnit *const unit)
{
for(std::vector<CUnit *>::iterator i(Units.begin()), end(Units.end());
i != end; ++i) {
for (std::vector<CUnit *>::iterator i(Units.begin()), end(Units.end()); i != end; ++i) {
if ((*i) == unit) {
Units.erase(i);
return;
@ -270,12 +201,12 @@ struct CUnitCache {
/**
** Insert new unit into tile cache.
** Sorted version for binary searching.
** Sorted version for binary searching.
**
** @param unit Unit pointer to place in cache.
** @return false if unit is already in cache and nothing is added.
*/
inline bool InsertS(CUnit *unit) {
bool InsertS(CUnit *unit) {
if (!binary_search(Units.begin(), Units.end(), unit))
{
Units.insert(std::lower_bound(Units.begin(), Units.end(), unit), unit);
@ -284,15 +215,17 @@ struct CUnitCache {
return false;
}
/**
** Insert new unit into tile cache.
**
** @param unit Unit pointer to place in cache.
*/
inline void Insert(CUnit *unit) {
void Insert(CUnit *unit) {
Units.push_back(unit);
}
public:
std::vector<CUnit *> Units;
};

View file

@ -81,15 +81,22 @@ static CGraphic *AlphaFogG;
----------------------------------------------------------------------------*/
struct _filter_flags {
const CPlayer *player;
int fogmask;
_filter_flags(const CPlayer &p, int m) : player(&p), fogmask(m) {}
inline void operator() (const CUnit *const unit) {
class _filter_flags
{
public:
_filter_flags(const CPlayer &p, int *fogmask) : player(&p), fogmask(fogmask)
{
Assert(fogmask != NULL);
}
void operator() (const CUnit *const unit) const {
if (!unit->IsVisibleAsGoal(*player)) {
fogmask &= ~unit->Type->FieldFlags;
*fogmask &= ~unit->Type->FieldFlags;
}
}
private:
const CPlayer *player;
int *fogmask;
};
/**
@ -104,10 +111,11 @@ struct _filter_flags {
*/
int MapFogFilterFlags(CPlayer &player, const unsigned int index, int mask)
{
_filter_flags filter(player, -1);
Map.Field(index)->UnitCache.for_each(filter);
return mask & filter.fogmask;
int fogMask = mask;
_filter_flags filter(player, &fogMask);
Map.Field(index)->UnitCache.for_each(filter);
return fogMask;
}
int MapFogFilterFlags(CPlayer &player, const Vec2i &pos, int mask)

View file

@ -681,16 +681,21 @@ void MarkUnitFieldFlags(const CUnit &unit)
} while (--h);
}
struct _UnmarkUnitFieldFlags {
const CUnit *const main;
CMapField *mf;
_UnmarkUnitFieldFlags(const CUnit &unit)
: main(&unit) {}
inline void operator () (CUnit *const unit) {
class _UnmarkUnitFieldFlags
{
public:
_UnmarkUnitFieldFlags(const CUnit &unit, CMapField *mf) : main(&unit), mf(mf)
{}
void operator () (CUnit *const unit) const
{
if (main != unit && unit->CurrentAction() != UnitActionDie) {
mf->Flags |= unit->Type->FieldFlags;
}
}
private:
const CUnit *const main;
CMapField *mf;
};
@ -701,24 +706,22 @@ struct _UnmarkUnitFieldFlags {
*/
void UnmarkUnitFieldFlags(const CUnit &unit)
{
CMapField *mf;
const unsigned int flags = ~unit.Type->FieldFlags; //
int w, h = unit.Type->TileHeight; // Tile height of the unit.
const int width = unit.Type->TileWidth; // Tile width of the unit.
const unsigned int flags = ~unit.Type->FieldFlags;
const int width = unit.Type->TileWidth;
int h = unit.Type->TileHeight;
unsigned int index = unit.Offset;
if (unit.Type->Vanishes) {
return ;
}
_UnmarkUnitFieldFlags funct(unit);
do {
mf = Map.Field(index);
w = width;
CMapField *mf = Map.Field(index);
int w = width;
do {
mf->Flags &= flags;//clean flags
funct.mf = mf;
_UnmarkUnitFieldFlags funct(unit, mf);
mf->UnitCache.for_each(funct);
++mf;
} while(--w);
@ -1201,64 +1204,63 @@ void UnitGoesOutOfFog(CUnit &unit, const CPlayer &player)
}
template<const bool MARK>
struct _TileSeen {
const CPlayer *player;
int cloak;
class _TileSeen
{
public:
_TileSeen(const CPlayer &p , int c) : player(&p), cloak(c)
{}
_TileSeen(const CPlayer &p , int c): player(&p), cloak(c) {}
inline void operator() ( CUnit *const unit) {
if (cloak == (int)unit->Type->PermanentCloak) {
const int p = player->Index;
if(MARK) {
//
// If the unit goes out of fog, this can happen for any player that
// this player shares vision with, and can't YET see the unit.
// It will be able to see the unit after the Unit->VisCount ++
//
if (!unit->VisCount[p]) {
for (int pi = 0; pi < PlayerMax; ++pi) {
if ((pi == p /*player->Index*/) ||
player->IsBothSharedVision(Players[pi])) {
if (!unit->IsVisible(Players[pi])) {
UnitGoesOutOfFog(*unit, Players[pi]);
}
void operator() (CUnit *const unit) const {
if (cloak != (int)unit->Type->PermanentCloak) {
return ;
}
const int p = player->Index;
if (MARK) {
// If the unit goes out of fog, this can happen for any player that
// this player shares vision with, and can't YET see the unit.
// It will be able to see the unit after the Unit->VisCount ++
if (!unit->VisCount[p]) {
for (int pi = 0; pi < PlayerMax; ++pi) {
if ((pi == p /*player->Index*/)
|| player->IsBothSharedVision(Players[pi])) {
if (!unit->IsVisible(Players[pi])) {
UnitGoesOutOfFog(*unit, Players[pi]);
}
}
}
unit->VisCount[p/*player->Index*/]++;
} else {
/*
* HACK: UGLY !!!
* There is bug in Seen code conneded with
* UnitActionDie and Cloacked units.
*/
if(!unit->VisCount[p] && unit->CurrentAction() == UnitActionDie)
{
return;
}
}
unit->VisCount[p/*player->Index*/]++;
} else {
/*
* HACK: UGLY !!!
* There is bug in Seen code conneded with
* UnitActionDie and Cloacked units.
*/
if (!unit->VisCount[p] && unit->CurrentAction() == UnitActionDie) {
return;
}
Assert(unit->VisCount[p]);
unit->VisCount[p]--;
//
// If the unit goes under of fog, this can happen for any player that
// this player shares vision to. First of all, before unmarking,
// every player that this player shares vision to can see the unit.
// Now we have to check who can't see the unit anymore.
//
if (!unit->VisCount[p]) {
for (int pi = 0; pi < PlayerMax; ++pi) {
if (pi == p/*player->Index*/ ||
player->IsBothSharedVision(Players[pi])) {
if (!unit->IsVisible(Players[pi])) {
UnitGoesUnderFog(*unit, Players[pi]);
}
Assert(unit->VisCount[p]);
unit->VisCount[p]--;
// If the unit goes under of fog, this can happen for any player that
// this player shares vision to. First of all, before unmarking,
// every player that this player shares vision to can see the unit.
// Now we have to check who can't see the unit anymore.
if (!unit->VisCount[p]) {
for (int pi = 0; pi < PlayerMax; ++pi) {
if (pi == p/*player->Index*/ ||
player->IsBothSharedVision(Players[pi])) {
if (!unit->IsVisible(Players[pi])) {
UnitGoesUnderFog(*unit, Players[pi]);
}
}
}
}
}
}
private:
const CPlayer *player;
int cloak;
};
/**

View file

@ -229,94 +229,86 @@ CUnit *ResourceDepositOnMap(const Vec2i &pos, int resource)
-- Finding units for attack
----------------------------------------------------------------------------*/
struct BestTargetFinder {
const CUnit *attacker;
const int range;
CUnit *best_unit;
int best_cost;
class BestTargetFinder
{
public:
BestTargetFinder(const CUnit &a, int r) :
attacker(&a), range(r)
{}
CUnit *Find(CUnit* table[], const int table_size) const
{
return Find(table, table + table_size);
}
BestTargetFinder(const CUnit &a, int r) : attacker(&a), range(r),
best_unit(0), best_cost(INT_MAX) {};
CUnit *Find(CUnitCache &cache) const
{
return Find(cache.begin(), cache.end());
}
inline void operator() (CUnit *const dest) {
private:
template <typename Iterator>
CUnit *Find(Iterator begin, Iterator end) const
{
CUnit *enemy = NULL;
int best_cost = INT_MAX;
for (Iterator it = begin; it != end; ++it) {
const int cost = ComputeCost(*it);
if (cost < best_cost) {
enemy = *it;
best_cost = cost;
}
}
return enemy;
}
int ComputeCost(CUnit *const dest) const
{
const CPlayer &player = *attacker->Player;
const CUnitType &type = *attacker->Type;
const CUnitType &dtype = *dest->Type;
const int attackrange = attacker->Stats->Variables[ATTACKRANGE_INDEX].Max;
if (!player.IsEnemy(*dest)) { // a friend or neutral
return;
if (!player.IsEnemy(*dest) // a friend or neutral
|| !dest->IsVisibleAsGoal(player)
|| !CanTarget(&type, &dtype)) {
return INT_MAX;
}
// Unit in range ?
const int d = attacker->MapDistanceTo(*dest);
if (d > range || !UnitReachable(*attacker, *dest, attackrange)) {
return INT_MAX;
}
if (!dest->IsVisibleAsGoal(player)) {
return;
}
const CUnitType *const type = attacker->Type;
const CUnitType *const dtype = dest->Type;
if (!CanTarget(type, dtype)) { // can't be attacked.
return;
}
//
// Unit in attack range?
//
int d = attacker->MapDistanceTo(*dest);
// Use Circle, not square :)
if (d > range) {
return;
}
//
// Calculate the costs to attack the unit.
// Unit with the smallest attack costs will be taken.
//
int attackrange = attacker->Stats->Variables[ATTACKRANGE_INDEX].Max;
int cost = 0;
//
// Priority 0-255
//
cost -= dtype->Priority * PRIORITY_FACTOR;
//
cost -= dtype.Priority * PRIORITY_FACTOR;
// Remaining HP (Health) 0-65535
//
cost += dest->Variable[HP_INDEX].Value * HEALTH_FACTOR;
if (d <= attackrange && d >= type->MinAttackRange) {
if (d <= attackrange && d >= type.MinAttackRange) {
cost += d * INRANGE_FACTOR;
cost -= INRANGE_BONUS;
} else {
cost += d * DISTANCE_FACTOR;
}
//
// Unit can attack back.
//
if (CanTarget(dtype, type)) {
if (CanTarget(&dtype, &type)) {
cost -= CANATTACK_BONUS;
}
//
// Take this target?
//
if (cost < best_cost && (d <= attackrange ||
UnitReachable(*attacker, *dest, attackrange))) {
best_unit = dest;
best_cost = cost;
}
}
CUnit *Find(CUnit* table[], const int table_size) {
for (int i = 0; i < table_size; ++i) {
this->operator() (table[i]);
}
return best_unit;
}
CUnit *Find(CUnitCache &cache) {
cache.for_each(*this);
return best_unit;
return cost;
}
private:
const CUnit *attacker;
const int range;
};
/**
@ -330,14 +322,8 @@ struct BestTargetFinder {
** @note Limited to attack range smaller than 16.
** @note Will be moved to unit_ai.c soon.
*/
struct BestRangeTargetFinder {
const CUnit *attacker;
const int range;
CUnit *best_unit;
int best_cost;
int good[32*32];
int bad[32*32];
class BestRangeTargetFinder {
public:
/**
** @param a Find in distance for this unit.
** @param range Distance range to look.
@ -349,19 +335,35 @@ struct BestRangeTargetFinder {
memset(bad, 0 , sizeof(int) * 32 * 32);
};
struct FillBadGood {
const CUnit *attacker;
const int range;
int enemy_count;
int *good;
int *bad;
class FillBadGood
{
public:
FillBadGood(const CUnit &a, int r, int *g, int *b):
attacker(&a), range(r),
enemy_count(0), good(g), bad(b) {
enemy_count(0), good(g), bad(b)
{
}
inline void operator() (CUnit *const dest)
int Fill(CUnit *table[], const int table_size)
{
return Fill(table, table + table_size);
}
int Fill(CUnitCache &cache)
{
return Fill(cache.begin(), cache.end());
}
private:
template <typename Iterator>
int Fill(Iterator begin, Iterator end)
{
for (Iterator it = begin; it != end; ++it) {
Compute(*it);
}
return enemy_count;
}
void Compute(CUnit *const dest)
{
const CPlayer &player = *attacker->Player;
@ -370,18 +372,16 @@ struct BestRangeTargetFinder {
return;
}
const CUnitType *const type = attacker->Type;
const CUnitType *const dtype = dest->Type;
const CUnitType &type = *attacker->Type;
const CUnitType &dtype = *dest->Type;
// won't be a target...
if (!CanTarget(type, dtype)) { // can't be attacked.
if (!CanTarget(&type, &dtype)) { // can't be attacked.
dest->CacheLock = 1;
return;
}
//
// Calculate the costs to attack the unit.
// Unit with the smallest attack costs will be taken.
//
int cost = 0;
const int hp_damage_evaluate =
@ -399,65 +399,46 @@ struct BestRangeTargetFinder {
// FIXME : assume that PRIORITY_FACTOR>HEALTH_FACTOR
cost = HEALTH_FACTOR * (2 * hp_damage_evaluate -
dest->Variable[HP_INDEX].Value) /
(dtype->TileWidth * dtype->TileWidth);
(dtype.TileWidth * dtype.TileWidth);
if (cost < 1) {
cost = 1;
}
cost = (-cost);
} else {
//
// Priority 0-255
//
cost += dtype->Priority * PRIORITY_FACTOR;
//
cost += dtype.Priority * PRIORITY_FACTOR;
// Remaining HP (Health) 0-65535
//
// Give a boost to unit we can kill in one shoot only
//
// calculate HP which will remain in the enemy unit, after hit
//
int effective_hp =
(dest->Variable[HP_INDEX].Value - 2 * hp_damage_evaluate);
int effective_hp = (dest->Variable[HP_INDEX].Value - 2 * hp_damage_evaluate);
//
// Unit we won't kill are evaluated the same
//
if (effective_hp > 0) {
effective_hp = 0;
}
//
// Unit we are sure to kill are all evaluated the same (except PRIORITY)
//
if (effective_hp < -hp_damage_evaluate) {
effective_hp = -hp_damage_evaluate;
}
//
// Here, effective_hp vary from -hp_damage_evaluate (unit will be killed) to 0 (unit can't be killed)
// => we prefer killing rather than only hitting...
//
cost += -effective_hp * HEALTH_FACTOR;
//
// Unit can attack back.
//
if (CanTarget(dtype, type)) {
if (CanTarget(&dtype, &type)) {
cost += CANATTACK_BONUS;
}
//
// the cost may be divided accros multiple cells
//
cost = cost / (dtype->TileWidth * dtype->TileWidth);
cost = cost / (dtype.TileWidth * dtype.TileWidth);
if (cost < 1) {
cost = 1;
}
//
// Removed Unit's are in bunkers
//
int d;
if (attacker->Removed) {
d = attacker->Container->MapDistanceTo(*dest);
@ -465,8 +446,7 @@ struct BestRangeTargetFinder {
d = attacker->MapDistanceTo(*dest);
}
int attackrange =
attacker->Stats->Variables[ATTACKRANGE_INDEX].Max;
int attackrange = attacker->Stats->Variables[ATTACKRANGE_INDEX].Max;
if (d <= attackrange ||
(d <= range && UnitReachable(*attacker, *dest, attackrange))) {
++enemy_count;
@ -475,15 +455,15 @@ struct BestRangeTargetFinder {
}
}
const int missile_range = type->Missile.Missile->Range + range - 1;
const int missile_range = type.Missile.Missile->Range + range - 1;
const int x = dest->tilePos.x - attacker->tilePos.x + missile_range + 1;
const int y = dest->tilePos.y - attacker->tilePos.y + missile_range + 1;
// Mark the good/bad array...
int yy_offset = x + y * 32;
for (int yy = 0; yy < dtype->TileHeight; ++yy) {
for (int yy = 0; yy < dtype.TileHeight; ++yy) {
if ((y + yy >= 0) && (y + yy < 2 * missile_range + 1)) {
for (int xx = 0; xx < dtype->TileWidth; ++xx) {
for (int xx = 0; xx < dtype.TileWidth; ++xx) {
if ((x + xx >= 0) && (x + xx < 2 * missile_range + 1)) {
if (cost < 0) {
good[yy_offset + xx] -= cost;
@ -495,50 +475,63 @@ struct BestRangeTargetFinder {
}
yy_offset += 32;
}
}
inline int Fill(CUnit *table[], const int table_size) {
for (int i = 0; i < table_size; ++i) {
this->operator() (table[i]);
}
return enemy_count;
}
inline int Fill(CUnitCache &cache) {
cache.for_each(*this);
return enemy_count;
}
private:
const CUnit *attacker;
const int range;
int enemy_count;
int *good;
int *bad;
};
inline void operator() (CUnit *const dest) {
CUnit *Find(CUnit* table[], const int table_size) {
FillBadGood(*attacker, range, good, bad).Fill(table, table_size);
return Find(table, table + table_size);
}
CUnit *Find(CUnitCache &cache) {
FillBadGood(*attacker, range, good, bad).Fill(cache);
return Find(cache.begin(), cache.end());
}
private:
template <typename Iterator>
CUnit *Find(Iterator begin, Iterator end)
{
for (Iterator it = begin; it != end; ++it) {
Compute(*it);
}
return best_unit;
}
void Compute(CUnit *const dest)
{
if (dest->CacheLock) {
dest->CacheLock = 0;
return;
}
const CUnitType *const type = attacker->Type;
const CUnitType *const dtype = dest->Type;
const int missile_range = type->Missile.Missile->Range + range - 1;
const CUnitType &type = *attacker->Type;
const CUnitType &dtype = *dest->Type;
const int missile_range = type.Missile.Missile->Range + range - 1;
int x,y;
// put in x-y the real point which will be hit...
// (only meaningful when dtype->TileWidth > 1)
if (attacker->tilePos.x < dest->tilePos.x) {
x = dest->tilePos.x;
} else if (attacker->tilePos.x > dest->tilePos.x + dtype->TileWidth - 1) {
x = dest->tilePos.x + dtype->TileWidth - 1;
} else if (attacker->tilePos.x > dest->tilePos.x + dtype.TileWidth - 1) {
x = dest->tilePos.x + dtype.TileWidth - 1;
} else {
x = attacker->tilePos.x;
}
if (attacker->tilePos.y < dest->tilePos.y) {
y = dest->tilePos.y;
} else if (attacker->tilePos.y > dest->tilePos.y + dtype->TileHeight - 1) {
y = dest->tilePos.y + dtype->TileHeight - 1;
} else if (attacker->tilePos.y > dest->tilePos.y + dtype.TileHeight - 1) {
y = dest->tilePos.y + dtype.TileHeight - 1;
} else {
y = attacker->tilePos.y;
}
@ -550,12 +543,12 @@ struct BestRangeTargetFinder {
int sbad = 0;
int sgood = 0;
int yy = -(type->Missile.Missile->Range - 1);
int yy = -(type.Missile.Missile->Range - 1);
int yy_offset = x + yy * 32;
for (;yy <= type->Missile.Missile->Range - 1; ++yy) {
for (;yy <= type.Missile.Missile->Range - 1; ++yy) {
if ((y + yy >= 0) && ((y + yy) < 2 * missile_range + 1)) {
for (int xx = -(type->Missile.Missile->Range - 1);
xx <= type->Missile.Missile->Range - 1; ++xx) {
for (int xx = -(type.Missile.Missile->Range - 1);
xx <= type.Missile.Missile->Range - 1; ++xx) {
if ((x + xx >= 0) && ((x + xx) < 2 * missile_range + 1)) {
sbad += bad[yy_offset + xx];
sgood += good[yy_offset + xx];
@ -582,20 +575,13 @@ struct BestRangeTargetFinder {
}
inline CUnit *Find( CUnit* table[], const int table_size) {
FillBadGood(*attacker, range, good, bad).Fill(table, table_size);
for (int i = 0; i < table_size; ++i) {
this->operator() (table[i]);
}
return best_unit;
}
inline CUnit *Find(CUnitCache &cache) {
FillBadGood(*attacker, range, good, bad).Fill(cache);
cache.for_each(*this);
return best_unit;
}
private:
const CUnit *attacker;
const int range;
CUnit *best_unit;
int best_cost;
int good[32*32];
int bad[32*32];
};
struct CompareUnitDistance {
@ -630,13 +616,11 @@ CUnit *AutoAttackUnitsInDistance(const CUnit &unit, int range,
CUnitCache &autotargets)
{
// if necessary, take possible damage on allied units into account...
if (unit.Type->Missile.Missile->Range > 1 &&
(range + unit.Type->Missile.Missile->Range < 15)) {
if (unit.Type->Missile.Missile->Range > 1
&& (range + unit.Type->Missile.Missile->Range < 15)) {
return BestRangeTargetFinder(unit, range).Find(autotargets);
} else {
//
// Find the best unit to auto attack
//
return BestTargetFinder(unit, range).Find(autotargets);
}
}