Permalink
Browse files

Removed redumental TMT_SURFACE_WATER layer; improved getThreat() calc…

…aultion; fixed a crash when enemy unit was out of map bounds; fixed calculation of maxPower per layer
  • Loading branch information...
1 parent 85ff7d8 commit b86dbf7d2392d2e9f145faaa288c8ff0212adb9f @slogic slogic committed Dec 25, 2010
Showing with 112 additions and 83 deletions.
  1. +97 −75 CThreatMap.cpp
  2. +15 −8 CThreatMap.h
View
@@ -13,35 +13,29 @@
CThreatMap::CThreatMap(AIClasses *ai) {
this->ai = ai;
- X = ai->cb->GetMapWidth() / (HEIGHT2SLOPE*I_MAP_RES);
- Z = ai->cb->GetMapHeight() / (HEIGHT2SLOPE*I_MAP_RES);
- REAL = HEIGHT2SLOPE * HEIGHT2REAL * I_MAP_RES;
+ // NOTE: X & Z are in pathgraph resolution
+ X = int(ai->cb->GetMapWidth() / (PATH2SLOPE * SLOPE2HEIGHT));
+ Z = int(ai->cb->GetMapHeight() / (PATH2SLOPE * SLOPE2HEIGHT));
lastUpdateFrame = 0;
maps[TMT_AIR] = new float[X*Z];
maps[TMT_SURFACE] = new float[X*Z];
- maps[TMT_SURFACE_WATER] = new float[X*Z];
maps[TMT_UNDERWATER] = new float[X*Z];
#if !defined(BUILDING_AI_FOR_SPRING_0_81_2)
handles[TMT_AIR] = ai->cb->DebugDrawerAddOverlayTexture(maps[TMT_AIR], X, Z);
- ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_AIR], -0.95f, -0.95f);
+ ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_AIR], -0.95f, -0.8f);
ai->cb->DebugDrawerSetOverlayTextureSize(handles[TMT_AIR], 0.4f, 0.4f);
ai->cb->DebugDrawerSetOverlayTextureLabel(handles[TMT_AIR], "Air ThreatMap");
handles[TMT_SURFACE] = ai->cb->DebugDrawerAddOverlayTexture(maps[TMT_SURFACE], X, Z);
- ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_SURFACE], -0.95f, -0.5f);
+ ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_SURFACE], -0.95f, -0.2f);
ai->cb->DebugDrawerSetOverlayTextureSize(handles[TMT_SURFACE], 0.4f, 0.4f);
ai->cb->DebugDrawerSetOverlayTextureLabel(handles[TMT_SURFACE], "Surface ThreatMap");
- handles[TMT_SURFACE_WATER] = ai->cb->DebugDrawerAddOverlayTexture(maps[TMT_SURFACE_WATER], X, Z);
- ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_SURFACE_WATER], -0.95f, -0.05f);
- ai->cb->DebugDrawerSetOverlayTextureSize(handles[TMT_SURFACE_WATER], 0.4f, 0.4f);
- ai->cb->DebugDrawerSetOverlayTextureLabel(handles[TMT_SURFACE_WATER], "Surface + Underwater ThreatMap");
-
handles[TMT_UNDERWATER] = ai->cb->DebugDrawerAddOverlayTexture(maps[TMT_UNDERWATER], X, Z);
- ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_UNDERWATER], -0.95f, 0.45f);
+ ai->cb->DebugDrawerSetOverlayTexturePos(handles[TMT_UNDERWATER], -0.95f, 0.4f);
ai->cb->DebugDrawerSetOverlayTextureSize(handles[TMT_UNDERWATER], 0.4f, 0.4f);
ai->cb->DebugDrawerSetOverlayTextureLabel(handles[TMT_UNDERWATER], "Underwater ThreatMap");
#endif
@@ -63,16 +57,16 @@ CThreatMap::~CThreatMap() {
}
void CThreatMap::reset() {
- std::map<ThreatMapType, float*>::iterator i;
+ std::map<ThreatMapType, float*>::iterator it;
// NOTE: no threat value equals to ONE, not ZERO!
- for (i = maps.begin(); i != maps.end(); ++i) {
- maxPower[i->first] = 1.0f;
- std::fill_n(i->second, X*Z, 1.0f);
+ for (it = maps.begin(); it != maps.end(); ++it) {
+ maxPower[it->first] = 1.0f;
+ std::fill_n(it->second, X*Z, 1.0f);
}
}
-float *CThreatMap::getMap(ThreatMapType type) {
- std::map<ThreatMapType,float*>::iterator i = maps.find(type);
+const float* CThreatMap::getMap(ThreatMapType type) {
+ std::map<ThreatMapType,float*>::const_iterator i = maps.find(type);
if (i == maps.end())
return NULL;
return i->second;
@@ -82,63 +76,74 @@ float CThreatMap::getThreat(float3 center, float radius, ThreatMapType type) {
if (type == TMT_NONE)
return 1.0f;
- center.CheckInBounds();
+ int i = int(round(center.z / PATH2REAL));
+ int j = int(round(center.x / PATH2REAL));
+ const float* tmData = maps[type];
- int i = center.z / REAL;
- int j = center.x / REAL;
- const float* map = maps[type];
+ assert(tmData != NULL);
- if (radius < EPS)
- return map[ID(j, i)];
+ if (radius < EPS) {
+ checkInBounds(j, i);
+ return tmData[ID(j, i)];
+ }
int sectorsProcessed = 0;
- int R = ceil(radius / REAL);
+ int R = int(round(radius / PATH2REAL));
float power = 0.0f;
+
+ // FIXME: search within circle instead of square
for (int z = -R; z <= R; z++) {
- int zz = z + i;
+ int zz = i + z;
- if (zz > Z-1 || zz < 0)
- continue;
-
- for (int x = -R; x <= R; x++) {
- int xx = x+j;
- if (xx < X-1 && xx >= 0) {
- power += map[ID(xx,zz)];
- sectorsProcessed++;
+ if (zz >= 0 && zz < Z) {
+ for (int x = -R; x <= R; x++) {
+ int xx = j + x;
+ if (xx >= 0 && xx < X) {
+ power += tmData[ID(xx, zz)];
+ sectorsProcessed++;
+ }
}
}
}
- // calculate number of sectors in R x R...
- R = 2 * R + 1;
+ // calculate total number of sectors within requested area...
+ R = R + R + 1;
R *= R;
// fixing area threat for map edges...
if (sectorsProcessed < R)
power += (R - sectorsProcessed);
- return power / R;
+ return (power / R);
}
-float CThreatMap::getThreat(float3 &center, float radius, CGroup *group) {
- ThreatMapType type = TMT_NONE;
+float CThreatMap::getThreat(const float3& center, float radius, CGroup* group) {
+ float temp, result = 1.0f;
// TODO: deal with LAND units when they are temporary under water
// TODO: deal with units which have tags LAND|SUB
// TODO: dealth with units which have tags AIR|SUB
- // NOTE: we do not support walking ships
-
- if ((group->cats&LAND).any())
- type = TMT_SURFACE; // hovers go here too because they can't be hit by torpedo
- else if ((group->cats&AIR).any())
- type = TMT_AIR;
- else if ((group->cats&SEA).any())
- type = TMT_SURFACE_WATER;
- else if ((group->cats&SUB).any())
- type = TMT_UNDERWATER;
+ if ((group->cats&AIR).any()) {
+ temp = getThreat(center, radius, TMT_AIR);
+ if (temp > 1.0f) result += temp - 1.0f;
+ }
+ if ((group->cats&SUB).any()) {
+ temp = getThreat(center, radius, TMT_UNDERWATER);
+ if (temp > 1.0f) result += temp - 1.0f;
+ }
+ // NOTE: hovers (LAND|SEA) can't be hit by underwater weapons that is why
+ // LAND tag check is a priority over SEA below
+ if ((group->cats&LAND).any()) {
+ temp = getThreat(center, radius, TMT_SURFACE);
+ if (temp > 1.0f) result += temp - 1.0f;
+ }
+ else if ((group->cats&SEA).any() && (group->cats&SUB).none()) {
+ temp = getThreat(center, radius, TMT_UNDERWATER);
+ if (temp > 1.0f) result += temp - 1.0f;
+ }
- return getThreat(center, radius, type);
+ return result;
}
void CThreatMap::update(int frame) {
@@ -147,9 +152,9 @@ void CThreatMap::update(int frame) {
if ((frame - lastUpdateFrame) < MULTIPLEXER)
return;
- const bool isWaterMap = ai->gamemap->IsWaterMap();
+ const bool isWaterMap = !ai->gamemap->IsWaterFreeMap();
std::list<ThreatMapType> activeTypes;
- std::list<ThreatMapType>::iterator itMapType;
+ std::list<ThreatMapType>::const_iterator itMapType;
reset();
@@ -173,42 +178,36 @@ void CThreatMap::update(int frame) {
if ((ecats&AIR).any() && (ecats&ASSAULT).none())
continue; // ignore air fighters & bombers
+ // FIXME: using maxWeaponRange below (twice) is WRONG; we need
+ // to calculate different max. ranges per each threatmap layer
+
// FIXME: think smth cleverer
if (ud->maxWeaponRange > MAX_WEAPON_RANGE_FOR_TM)
continue; // ignore units with extra large range
const float3 upos = ai->cbc->GetUnitPos(uid);
- /*
- if (upos.y < 0.0f && (ecats&TORPEDO).none())
- continue; // ignore units which can't shoot under the water
- */
-
activeTypes.clear();
- if ((ecats&ANTIAIR).any()) {
+ if ((ecats&ANTIAIR).any() && upos.y >= 0.0f) {
activeTypes.push_back(TMT_AIR);
}
if (((ecats&SEA).any() || upos.y >= 0.0f)
&& ((ecats&ANTIAIR).none() || (catsCanShootGround&ecats).any())) {
activeTypes.push_back(TMT_SURFACE);
- if (isWaterMap)
- activeTypes.push_back(TMT_SURFACE_WATER);
}
- // NOTE: TMT_SURFACE_WATER map can exist twice in a list which is ok
if (isWaterMap && (ecats&TORPEDO).any()) {
activeTypes.push_back(TMT_UNDERWATER);
- activeTypes.push_back(TMT_SURFACE_WATER);
}
if (activeTypes.empty())
continue;
- const float uRealX = upos.x/REAL;
- const float uRealZ = upos.z/REAL;
- const float range = (ud->maxWeaponRange + 100.0f) / REAL;
+ const float uRealX = upos.x / PATH2REAL;
+ const float uRealZ = upos.z / PATH2REAL;
+ const float range = (ud->maxWeaponRange + 100.0f) / PATH2REAL;
float powerT = ai->cbc->GetUnitPower(uid);
const float power = (ecats&COMMANDER).any() ? powerT/20.0f : powerT;
float3 pos(0.0f, 0.0f, 0.0f);
@@ -221,20 +220,24 @@ void CThreatMap::update(int frame) {
if (pos.Length2D() <= range) {
pos.x += uRealX;
pos.z += uRealZ;
- const unsigned int mx = (unsigned int) round(pos.x);
- const unsigned int mz = (unsigned int) round(pos.z);
- if (mx < X && mz < Z) {
+ const int mx = int(round(pos.x));
+ const int mz = int(round(pos.z));
+ if (isInBounds(mx, mz)) {
for (itMapType = activeTypes.begin(); itMapType != activeTypes.end(); ++itMapType) {
- maps[*itMapType][ID(mx, mz)] += power;
+ int id = ID(mx, mz);
+ maps[*itMapType][id] += power;
+ maxPower[*itMapType] = std::max(maps[*itMapType][id], maxPower[*itMapType]);
}
}
}
}
}
+ /*
for (itMapType = activeTypes.begin(); itMapType != activeTypes.end(); ++itMapType) {
maxPower[*itMapType] = std::max<float>(power, maxPower[*itMapType]);
}
+ */
}
#if !defined(BUILDING_AI_FOR_SPRING_0_81_2)
@@ -266,21 +269,40 @@ float CThreatMap::gauss(float x, float sigma, float mu) {
return a * b;
}
+void CThreatMap::checkInBounds(int& x, int& z) {
+ if (x < 0)
+ x = 0;
+ else if (x >= X)
+ x = X - 1;
+
+ if (z < 0)
+ z = 0;
+ else if (z >= Z)
+ z = Z - 1;
+}
+
void CThreatMap::visualizeMap(ThreatMapType type) {
- float *map = maps[type];
+ static const int figureID = 5;
+
+ std::map<ThreatMapType,float*>::const_iterator i = maps.find(type);
+
+ if (i == maps.end())
+ return;
+
+ const float* map = i->second;
float total = maxPower[type];
for (int z = 0; z < Z; z++) {
for (int x = 0; x < X; x++) {
- if (map[ID(x,z)] > 1.0f + EPSILON) {
- float3 p0(x*REAL, ai->cb->GetElevation(x*REAL,z*REAL), z*REAL);
+ if (map[ID(x,z)] > 1.0f + EPS) {
+ float3 p0(x * PATH2REAL, ai->cb->GetElevation(x*PATH2REAL,z*PATH2REAL), z*PATH2REAL);
float3 p1(p0);
- p1.y += (map[ID(x,z)]/total) * 300.0f;
- ai->cb->CreateLineFigure(p0, p1, 4, 10.0, MULTIPLEXER, 5);
+ p1.y += (map[ID(x,z)]/total) * 250.0f;
+ ai->cb->CreateLineFigure(p0, p1, 4, 10.0f, MULTIPLEXER, figureID);
}
}
}
- ai->cb->SetFigureColor(5, 1.0f, 0.0f, 0.0f, 1.0f);
+ ai->cb->SetFigureColor(figureID, 1.0f, 0.0f, 0.0f, 1.0f);
}
bool CThreatMap::switchDebugMode() {
View
@@ -7,37 +7,44 @@
class AIClasses;
class CGroup;
+// TODO: convert into flags?
enum ThreatMapType {
TMT_NONE = 0,
TMT_AIR,
TMT_SURFACE,
- TMT_SURFACE_WATER, // TMT_SURFACE + TMT_UNDERWATER
TMT_UNDERWATER,
TMT_LAST
};
class CThreatMap {
public:
- CThreatMap(AIClasses *ai);
+ CThreatMap(AIClasses* ai);
~CThreatMap();
void update(int frame);
float getThreat(float3 center, float radius, ThreatMapType type = TMT_SURFACE);
- float getThreat(float3 &center, float radius, CGroup *group);
- float *getMap(ThreatMapType);
+ float getThreat(const float3& center, float radius, CGroup* group);
+ const float* getMap(ThreatMapType);
bool switchDebugMode();
+ bool isInBounds(int x, int z) { return (x >= 0 && z >= 0 && x < X && z < Z); }
+ void checkInBounds(int& x, int& z);
- unsigned int X, Z;
- int RES;
+protected:
+ AIClasses* ai;
private:
- AIClasses* ai;
+ int X, Z;
+ // width & height of threat map (in pathgraph resolution)
int lastUpdateFrame;
- float REAL;
+ // not very helpful for now; will be really used when threatmap
+ // is shared between allied AIs
ThreatMapType drawMap;
+ // current threat map to visualize
std::map<ThreatMapType, float> maxPower;
+ // max threat per map
std::map<ThreatMapType, float*> maps;
+ // threatmap data
#if !defined(BUILDING_AI_FOR_SPRING_0_81_2)
std::map<ThreatMapType, int> handles;
// for visual debugging purposes

0 comments on commit b86dbf7

Please sign in to comment.