Rev.8022 fixed a warning, but broke the behavior of some method.
Here is the fix for these methods.
This commit is contained in:
parent
96dc321b38
commit
0e54eae28e
6 changed files with 339 additions and 400 deletions
src
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue