From 0e54eae28e3ffb83386efe2ad87c0ee711d8e2b2 Mon Sep 17 00:00:00 2001 From: joris <joris.dauphin@gmail.com> Date: Thu, 16 Feb 2012 14:59:44 +0100 Subject: [PATCH] Rev.8022 fixed a warning, but broke the behavior of some method. Here is the fix for these methods. --- src/ai/ai_force.cpp | 69 ++++----- src/ai/ai_plan.cpp | 47 +++--- src/include/unit_cache.h | 169 +++++++--------------- src/map/map_fog.cpp | 26 ++-- src/unit/unit.cpp | 128 +++++++++-------- src/unit/unit_find.cpp | 300 ++++++++++++++++++--------------------- 6 files changed, 339 insertions(+), 400 deletions(-) diff --git a/src/ai/ai_force.cpp b/src/ai/ai_force.cpp index 0a7a2eec5..c7218b3f4 100644 --- a/src/ai/ai_force.cpp +++ b/src/ai/ai_force.cpp @@ -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; diff --git a/src/ai/ai_plan.cpp b/src/ai/ai_plan.cpp index 15ec2c6b9..e90812cf1 100644 --- a/src/ai/ai_plan.cpp +++ b/src/ai/ai_plan.cpp @@ -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; } /** diff --git a/src/include/unit_cache.h b/src/include/unit_cache.h index 7e864579c..ddd6b25e1 100644 --- a/src/include/unit_cache.h +++ b/src/include/unit_cache.h @@ -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; }; diff --git a/src/map/map_fog.cpp b/src/map/map_fog.cpp index 392ef4351..3faf1153a 100644 --- a/src/map/map_fog.cpp +++ b/src/map/map_fog.cpp @@ -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) diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 40b0612bf..d6c022e43 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -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; }; /** diff --git a/src/unit/unit_find.cpp b/src/unit/unit_find.cpp index 5ac98088d..9e2eaf16d 100644 --- a/src/unit/unit_find.cpp +++ b/src/unit/unit_find.cpp @@ -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); } }