Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
slogic committed Dec 25, 2010
1 parent 85ff7d8 commit b86dbf7
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 83 deletions.
172 changes: 97 additions & 75 deletions CThreatMap.cpp
Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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) {
Expand All @@ -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();

Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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() {
Expand Down
23 changes: 15 additions & 8 deletions CThreatMap.h
Expand Up @@ -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
Expand Down

0 comments on commit b86dbf7

Please sign in to comment.