u8 SC2Map::getHeightCell( point* c ) { if( !isPlayableCell( c ) ) { printError( "Attempt to access data from unplayable cell (%d, %d)\n", c->pcx, c->pcy ); exit( -1 ); } if( c->pcx == point::pcNaN ) { printError( "Expected a cell point.\n" ); exit( -1 ); } point t_ur; t_ur.ptSet( c->pcx + 1, c->pcy + 1 ); point t_lr; t_lr.ptSet( c->pcx + 1, c->pcy ); point t_ll; t_ll.ptSet( c->pcx, c->pcy ); point t_ul; t_ul.ptSet( c->pcx, c->pcy + 1 ); // this isn't a well-defined concept for cells with // a bunch of neighboring heights, which is ok because // those kinds of cells don't usually render any interesting // game info because they are unpathable return (getHeight( &t_ur ) + getHeight( &t_lr ) + getHeight( &t_ll ) + getHeight( &t_ul )) / 4; }
float SC2Map::getShortestPathDistance( point* src, point* dst, PathType t ) { if( !isPlayableCell( src ) || !isPlayableCell( dst ) ) { return infinity; } Node* u = getPathNode( src, t ); Node* v = getPathNode( dst, t ); if( u == NULL || v == NULL ) { return infinity; } return getShortestPathDistance( u, v, t ); }
bool SC2Map::checkHasOpennessLastPass( point* c, PathType t ) { if( !isPlayableCell( c ) ) { return false; } return mapOpennessPrev[NUM_PATH_TYPES*(c->pcy*cxDimPlayable + c->pcx) + t] > -0.5f; }
float SC2Map::getOpennessLastPass( point* c, PathType t ) { if( !isPlayableCell( c ) ) { printError( "Attempt to access data from unplayable cell (%d, %d)\n.", c->pcx, c->pcy ); exit( -1 ); } return mapOpennessPrev[NUM_PATH_TYPES*(c->pcy*cxDimPlayable + c->pcx) + t]; }
bool SC2Map::checkHasOpenness( point* c, PathType t ) { if( !isPlayableCell( c ) ) { printError( "Attempt to access data from unplayable cell (%d, %d)\n.", c->pcx, c->pcy ); exit( -1 ); } return mapOpenness[NUM_PATH_TYPES*(c->pcy*cxDimPlayable + c->pcx) + t] > -0.5f; }
void SC2Map::setOpenness( point* c, PathType t, float o ) { if( !isPlayableCell( c ) ) { printError( "Attempt to access data from unplayable cell (%d, %d).\n", c->pcx, c->pcy ); exit( -1 ); } mapOpenness[NUM_PATH_TYPES*(c->pcy*cxDimPlayable + c->pcx) + t] = o; }
void SC2Map::setPathNode( point* c, PathType t, Node* u ) { if( !isPlayableCell( c ) ) { printError( "Attempt to access data from unplayable cell (%d, %d).\n", c->pcx, c->pcy ); exit( -1 ); } mapPathNodes[NUM_PATH_TYPES*(c->pcy*cxDimPlayable + c->pcx) + t] = u; }
Node* SC2Map::getPathNode( point* c, PathType t ) { if( !isPlayableCell( c ) ) { // allow the "getter" of nodes to simply return NULL when // access is out of bounds to simplify logic of algorithms // that start at a given cell and try to inspect the neighbors return NULL; } return mapPathNodes[NUM_PATH_TYPES*(c->pcy*cxDimPlayable + c->pcx) + t]; }
float SC2Map::getShortestPathDistance( point* p, Base* b, PathType t ) { if( !isPlayableCell( p ) ) { return infinity; } Node* u = getPathNode( p, t ); if( u == NULL ) { return infinity; } return getShortestPathDistance( u, b, t ); }
float SC2Map::calculateAverageOpennessInNeighborhood( point* p, float radius, PathType t ) { float oTotal = 0.0f; int cellsSampled = 0; int r = (int)(radius + 1.0f); for( int pci = -r; pci < r; ++pci ) { for( int pcj = -r; pcj < r; ++pcj ) { // only sample openness in circle // around the base float xsq = (float)(pci*pci); float ysq = (float)(pcj*pcj); if( sqrt( xsq + ysq ) > radius ) { continue; } ++cellsSampled; point c; c.pcSet( p->pcx + pci, p->pcy + pcj ); if( isPlayableCell( &c ) && checkHasOpenness( &c, t ) ) { oTotal += getOpenness( &c, t ); } } } return oTotal / (float)cellsSampled; }
int SC2Map::readPaintedPathingLayer( const HANDLE archive ) { char strFilename[] = "PaintedPathingLayer"; int bufferSize; u8* bufferFreeAfterUse; if( readArchiveFile( archive, strFilename, &bufferSize, &bufferFreeAfterUse ) < 0 ) { return -1; } bool continueProcessing = true; int expectedSize = 16 + 8*256*256; if( bufferSize < expectedSize ) { printWarning( "%s is invalid.\n", strFilename ); continueProcessing = false; } // position in the data buffer, skip opening words int buffpos = 16; for( int i = 0; i < 8*256*256; ++i ) { bool breakFromLoop = false; u8 type; memcpy( (void*) &type, (void*) &(bufferFreeAfterUse[buffpos]), 1 ); buffpos += 1; point c; int mcy = i / (8*256); int rmn = i % (4*256); int mcx = rmn / 4; c.mcSet( mcx, mcy ); if( !isPlayableCell( &c ) ) { continue; // just skip } switch( type ) { case 0x80: // no painted pathing break; case 0x00: // no ground/cwalk/build pathing! for( int t = 0; t < NUM_PATH_TYPES; ++t ) { setPathing( &c, (PathType)t, false ); } break; case 0x01: // YES ground (overrides!) for( int t = 0; t < NUM_PATH_TYPES; ++t ) { setPathing( &c, (PathType)t, true ); } break; case 0x81: // no building setPathing( &c, PATH_BUILDABLE, false ); setPathing( &c, PATH_BUILDABLE_MAIN, false ); break; default: printError( "Unknown triangle type in %s.\n", strFilename ); breakFromLoop = true; } if( breakFromLoop ) { continueProcessing = false; break; } } delete bufferFreeAfterUse; if( continueProcessing ) { // if we processed to the end with no problem, // report no problem return 0; } // otherwise report error return -1; }