// ============================================================== // ============================================================== // This file is part of Glest (www.glest.org) // // Copyright (C) 2001-2008 Martio Figueroa // // You can redistribute this code and/or modify it under // the terms of the GNU General Public License as published // by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version // ============================================================== #include "map.h" #include #include "tileset.h" #include "unit.h" #include "resource.h" #include "logger.h" #include "tech_tree.h" #include "config.h" #include "util.h" #include "game_settings.h" #include "platform_util.h" #include "pos_iterator.h" #include "faction.h" #include "command.h" #include "leak_dumper.h" using namespace Shared::Graphics; using namespace Shared::Util; using namespace Shared::Platform; namespace Glest{ namespace Game{ // ===================================================== // class Cell // ===================================================== Cell::Cell() { //game data for(int i = 0; i < fieldCount; ++i) { units[i]= NULL; unitsWithEmptyCellMap[i]=NULL; } height= 0; } // ==================== misc ==================== //returns if the cell is free bool Cell::isFree(Field field) const{ return getUnit(field)==NULL || getUnit(field)->isPutrefacting(); } // ===================================================== // class SurfaceCell // ===================================================== SurfaceCell::SurfaceCell(){ object= NULL; vertex= Vec3f(0.f); normal= Vec3f(0.f, 1.f, 0.f); surfaceType= -1; surfaceTexture= NULL; } SurfaceCell::~SurfaceCell(){ delete object; } bool SurfaceCell::isFree() const{ return object==NULL || object->getWalkable(); } void SurfaceCell::deleteResource(){ delete object; object= NULL; } void SurfaceCell::setExplored(int teamIndex, bool explored){ this->explored[teamIndex]= explored; } void SurfaceCell::setVisible(int teamIndex, bool visible){ this->visible[teamIndex]= visible; } // ===================================================== // class Map // ===================================================== // ===================== PUBLIC ======================== const int Map::cellScale= 2; const int Map::mapScale= 2; Map::Map(){ cells= NULL; surfaceCells= NULL; startLocations= NULL; } Map::~Map(){ Logger::getInstance().add("Cells", true); delete [] cells; cells = NULL; delete [] surfaceCells; surfaceCells = NULL; delete [] startLocations; startLocations = NULL; } int Map::getSurfaceCellArraySize() const { return (surfaceW * surfaceH); } SurfaceCell *Map::getSurfaceCell(int sx, int sy) const { int arrayIndex = sy * surfaceW + sx; if(arrayIndex >= getSurfaceCellArraySize()) { throw runtime_error("arrayIndex >= getSurfaceCellArraySize(), arrayIndex = " + intToStr(arrayIndex) + " surfaceW = " + intToStr(surfaceW) + " surfaceH = " + intToStr(surfaceH)); } else if(surfaceCells == NULL) { throw runtime_error("surfaceCells == NULL"); } return &surfaceCells[arrayIndex]; } int Map::getCellArraySize() const { return (w * h); } Cell *Map::getCell(int x, int y) const { int arrayIndex = y * w + x; if(arrayIndex >= getCellArraySize()) { throw runtime_error("arrayIndex >= getCellArraySize(), arrayIndex = " + intToStr(arrayIndex) + " w = " + intToStr(w) + " h = " + intToStr(h)); } else if(cells == NULL) { throw runtime_error("cells == NULL"); } return &cells[arrayIndex]; } Vec2i Map::getStartLocation(int locationIndex) const { if(locationIndex >= maxPlayers) { throw runtime_error("locationIndex >= maxPlayers"); } else if(startLocations == NULL) { throw runtime_error("startLocations == NULL"); } return startLocations[locationIndex]; } void Map::load(const string &path, TechTree *techTree, Tileset *tileset){ struct MapFileHeader{ int32 version; int32 maxPlayers; int32 width; int32 height; int32 altFactor; int32 waterLevel; int8 title[128]; int8 author[128]; int8 description[256]; }; try{ FILE *f= fopen(path.c_str(), "rb"); if(f!=NULL){ //read header MapFileHeader header; size_t readBytes = fread(&header, sizeof(MapFileHeader), 1, f); if(next2Power(header.width) != header.width){ throw runtime_error("Map width is not a power of 2"); } if(next2Power(header.height) != header.height){ throw runtime_error("Map height is not a power of 2"); } heightFactor= header.altFactor; waterLevel= static_cast((header.waterLevel-0.01f)/heightFactor); title= header.title; maxPlayers= header.maxPlayers; surfaceW= header.width; surfaceH= header.height; w= surfaceW*cellScale; h= surfaceH*cellScale; //start locations startLocations= new Vec2i[maxPlayers]; for(int i=0; isetVertex(Vec3f(i*mapScale, alt / heightFactor, j*mapScale)); } } //read surfaces for(int j=0; jsetSurfaceType(surf-1); } } //read objects and resources for(int j=0; jsetObject(NULL); } else if(objNumber <= Tileset::objCount){ Object *o= new Object(tileset->getObjectType(objNumber-1), sc->getVertex(),Vec2i(i, j)); sc->setObject(o); for(int k=0; kgetResourceTypeCount(); ++k){ const ResourceType *rt= techTree->getResourceType(k); if(rt->getClass()==rcTileset && rt->getTilesetObject()==objNumber){ o->setResource(rt, Vec2i(i, j)); } } } else{ const ResourceType *rt= techTree->getTechResourceType(objNumber - Tileset::objCount) ; Object *o= new Object(NULL, sc->getVertex(),Vec2i(i, j)); o->setResource(rt, Vec2i(i, j)); sc->setObject(o); } } } } else{ throw runtime_error("Can't open file"); } fclose(f); } catch(const exception &e){ SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,e.what()); throw runtime_error("Error loading map: "+ path+ "\n"+ e.what()); } } void Map::init(){ Logger::getInstance().add("Heightmap computations", true); smoothSurface(); computeNormals(); computeInterpolatedHeights(); computeNearSubmerged(); computeCellColors(); } // ==================== is ==================== bool Map::isInside(int x, int y) const{ return x>=0 && y>=0 && x=0 && sy>=0 && sxgetResource(); if(r != NULL) { if(r->getType() == rt) { resourcePos= pos + Vec2i(i,j); if(unit == NULL || unit->isBadHarvestPos(resourcePos) == false) { return true; } } } } } } if(fallbackToPeersHarvestingSameResource == true && unit != NULL) { // Look for another unit that is currently harvesting the same resource // type right now // Check the faction cache for a known position where we can harvest // this resource type Vec2i result = unit->getFaction()->getClosestResourceTypeTargetFromCache(unit, rt); if(result.x >= 0) { resourcePos = result; if(unit->getPos().dist(resourcePos) <= size) { return true; } } } return false; } //returns if there is a resource next to a unit, in "resourcePos" is stored the relative position of the resource bool Map::isResourceNear(const Vec2i &pos, int size, const ResourceType *rt, Vec2i &resourcePos) const { Vec2i p1 = pos + Vec2i(-1); Vec2i p2 = pos + Vec2i(size); Util::PerimeterIterator iter(p1, p2); while (iter.more()) { Vec2i cur = iter.next(); if (isInside(cur)) { Resource *r = getSurfaceCell(toSurfCoords(cur))->getResource(); if (r && r->getType() == rt) { resourcePos = cur; return true; } } } return false; } // ==================== free cells ==================== bool Map::isFreeCell(const Vec2i &pos, Field field) const { return isInside(pos) && getCell(pos)->isFree(field) && (field==fAir || getSurfaceCell(toSurfCoords(pos))->isFree()) && (field!=fLand || getDeepSubmerged(getCell(pos)) == false); } bool Map::isFreeCellOrHasUnit(const Vec2i &pos, Field field, const Unit *unit) const { if(isInside(pos)) { Cell *c= getCell(pos); if(c->getUnit(unit->getCurrField()) == unit) { if(unit->getCurrField() == fAir) { const SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos)); if(sc != NULL) { if(getDeepSubmerged(sc) == true) { return false; } else if(field == fLand) { if(sc->isFree() == false) { return false; } else if(c->getUnit(field) != NULL) { return false; } } } } return true; } else{ return isFreeCell(pos, field); } } return false; } bool Map::isAproxFreeCell(const Vec2i &pos, Field field, int teamIndex) const{ if(isInside(pos)){ const SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos)); if(sc->isVisible(teamIndex)){ return isFreeCell(pos, field); } else if(sc->isExplored(teamIndex)){ return field==fLand? sc->isFree() && !getDeepSubmerged(getCell(pos)): true; } else{ return true; } } return false; } bool Map::isFreeCells(const Vec2i & pos, int size, Field field) const { for(int i=pos.x; iisFree(field) = %d, getSurfaceCell(toSurfCoords(testPos))->isFree() = %d, getDeepSubmerged(getCell(testPos)) = %d\n",__FILE__,__FUNCTION__,__LINE__,testPos.getString().c_str(),field,getCell(testPos)->isFree(field),getSurfaceCell(toSurfCoords(testPos))->isFree(),getDeepSubmerged(getCell(testPos))); return false; } } } return true; } bool Map::isFreeCellsOrHasUnit(const Vec2i &pos, int size, Field field, const Unit *unit) const{ for(int i=pos.x; ihasCellMap()) { for (int y=0; y < ut->getSize(); ++y) { for (int x=0; x < ut->getSize(); ++x) { if (ut->getCellMapCell(x, y, facing)) { if (!isFreeCell(pos + Vec2i(x, y), field)) { return false; } } } } return true; } else { return isFreeCells(pos, ut->getSize(), field); } } // ==================== unit placement ==================== //checks if a unit can move from between 2 cells bool Map::canMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, std::map > > > *lookupCache) const { int size= unit->getType()->getSize(); Field field= unit->getCurrField(); if(lookupCache != NULL) { std::map > > >::const_iterator iterFind1 = lookupCache->find(pos1); if(iterFind1 != lookupCache->end()) { std::map > >::const_iterator iterFind2 = iterFind1->second.find(pos2); if(iterFind2 != iterFind1->second.end()) { std::map >::const_iterator iterFind3 = iterFind2->second.find(size); if(iterFind3 != iterFind2->second.end()) { std::map::const_iterator iterFind4 = iterFind3->second.find(field); if(iterFind4 != iterFind3->second.end()) { // Found this result in the cache return iterFind4->second; } } } } } for(int i=pos2.x; igetUnit(field) != unit) { if(isFreeCell(Vec2i(i, j), field) == false) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][size][field]=false; } return false; } } } else { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][size][field]=false; } return false; } } } if(unit == NULL || unit->isBadHarvestPos(pos2) == true) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][size][field]=false; } return false; } if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][size][field]=true; } return true; } //checks if a unit can move from between 2 cells using only visible cells (for pathfinding) bool Map::aproxCanMove(const Unit *unit, const Vec2i &pos1, const Vec2i &pos2, std::map > > > > *lookupCache) const { int size= unit->getType()->getSize(); int teamIndex= unit->getTeam(); Field field= unit->getCurrField(); if(lookupCache != NULL) { std::map > > > >::const_iterator iterFind1 = lookupCache->find(pos1); if(iterFind1 != lookupCache->end()) { std::map > > >::const_iterator iterFind2 = iterFind1->second.find(pos2); if(iterFind2 != iterFind1->second.end()) { std::map > >::const_iterator iterFind3 = iterFind2->second.find(teamIndex); if(iterFind3 != iterFind2->second.end()) { std::map >::const_iterator iterFind4 = iterFind3->second.find(size); if(iterFind4 != iterFind3->second.end()) { std::map::const_iterator iterFind5 = iterFind4->second.find(field); if(iterFind5 != iterFind4->second.end()) { // Found this result in the cache return iterFind5->second; } } } } } } //single cell units if(size == 1) { if(isAproxFreeCell(pos2, field, teamIndex) == false) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } if(pos1.x != pos2.x && pos1.y != pos2.y) { if(isAproxFreeCell(Vec2i(pos1.x, pos2.y), field, teamIndex) == false) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } if(isAproxFreeCell(Vec2i(pos2.x, pos1.y), field, teamIndex) == false) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } } if(unit == NULL || unit->isBadHarvestPos(pos2) == true) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=true; } return true; } //multi cell units else { for(int i = pos2.x; i < pos2.x + size; ++i) { for(int j = pos2.y; j < pos2.y + size; ++j) { if(isInside(i, j)) { if(getCell(i, j)->getUnit(unit->getCurrField()) != unit) { if(isAproxFreeCell(Vec2i(i, j), field, teamIndex) == false) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } } } else { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } } } if(unit == NULL || unit->isBadHarvestPos(pos2) == true) { if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=false; } return false; } if(lookupCache != NULL) { (*lookupCache)[pos1][pos2][teamIndex][size][field]=true; } return true; } } Vec2i Map::computeRefPos(const Selection *selection) const { Vec2i total= Vec2i(0); for(int i = 0; i < selection->getCount(); ++i) { if(selection == NULL || selection->getUnit(i) == NULL) { throw runtime_error("selection == NULL || selection->getUnit(i) == NULL"); } total = total + selection->getUnit(i)->getPos(); } return Vec2i(total.x / selection->getCount(), total.y / selection->getCount()); } Vec2i Map::computeDestPos( const Vec2i &refUnitPos, const Vec2i &unitPos, const Vec2i &commandPos) const { Vec2i pos; Vec2i posDiff = unitPos - refUnitPos; if(abs(posDiff.x) >= 3){ posDiff.x = posDiff.x % 3; } if(abs(posDiff.y) >= 3){ posDiff.y = posDiff.y % 3; } pos = commandPos + posDiff; clampPos(pos); return pos; } std::pair Map::getUnitDistanceToPos(const Unit *unit,Vec2i pos,const UnitType *ut) { if(unit == NULL) { throw runtime_error("unit == NULL"); } std::pair result(-1,Vec2i(0)); int unitId= unit->getId(); Vec2i unitPos= computeDestPos(unit->getPos(), unit->getPos(), pos); Vec2i start = pos - Vec2i(1); int unitTypeSize = 0; if(ut != NULL) { unitTypeSize = ut->getSize(); } Vec2i end = pos + Vec2i(unitTypeSize); for(int i = start.x; i <= end.x; ++i) { for(int j = start.y; j <= end.y; ++j){ Vec2i testPos(i,j); if(ut == NULL || isInUnitTypeCells(ut, pos,testPos) == false) { float distance = unitPos.dist(testPos); if(result.first < 0 || result.first > distance) { result.first = distance; result.second = testPos; } } } } return result; } const Unit * Map::findClosestUnitToPos(const Selection *selection, Vec2i originalBuildPos, const UnitType *ut) const { const Unit *closestUnit = NULL; Vec2i refPos = computeRefPos(selection); Vec2i pos = originalBuildPos; float bestRange = -1; Vec2i start = pos - Vec2i(1); int unitTypeSize = 0; if(ut != NULL) { unitTypeSize = ut->getSize(); } Vec2i end = pos + Vec2i(unitTypeSize); for(int i = 0; i < selection->getCount(); ++i) { const Unit *unit = selection->getUnit(i); int unitId= unit->getId(); Vec2i unitBuilderPos= computeDestPos(refPos, unit->getPos(), pos); for(int i = start.x; i <= end.x; ++i) { for(int j = start.y; j <= end.y; ++j){ Vec2i testPos(i,j); if(isInUnitTypeCells(ut, originalBuildPos,testPos) == false) { float distance = unitBuilderPos.dist(testPos); if(bestRange < 0 || bestRange > distance) { bestRange = distance; pos = testPos; closestUnit = unit; } } } } } return closestUnit; } Vec2i Map::findBestBuildApproach(Vec2i unitBuilderPos, Vec2i originalBuildPos, const UnitType *ut) const { Vec2i pos = originalBuildPos; float bestRange = -1; Vec2i start = pos - Vec2i(1); Vec2i end = pos + Vec2i(ut->getSize()); for(int i = start.x; i <= end.x; ++i) { for(int j = start.y; j <= end.y; ++j){ Vec2i testPos(i,j); if(isInUnitTypeCells(ut, originalBuildPos,testPos) == false) { float distance = unitBuilderPos.dist(testPos); if(bestRange < 0 || bestRange > distance) { bestRange = distance; pos = testPos; } } } } return pos; } bool Map::isNextToUnitTypeCells(const UnitType *ut, const Vec2i &pos, const Vec2i &testPos) const { bool isInsideDestUnitCells = isInUnitTypeCells(ut, pos,testPos); if(isInsideDestUnitCells == false) { Cell *testCell = getCell(testPos); for(int i=-1; i <= ut->getSize(); ++i){ for(int j = -1; j <= ut->getSize(); ++j) { Vec2i currPos = pos + Vec2i(i, j); if(isInside(currPos) == true) { //Cell *unitCell = getCell(currPos); //if(unitCell == testCell) { if(isNextTo(testPos,currPos) == true) { return true; } } } } } return false; } // is testPos in the cells of unitType where unitType's position is pos bool Map::isInUnitTypeCells(const UnitType *ut, const Vec2i &pos, const Vec2i &testPos) const { assert(ut!=NULL); if(ut == NULL) { throw runtime_error("ut == NULL"); } Cell *testCell = getCell(testPos); for(int i=0; i < ut->getSize(); ++i){ for(int j = 0; j < ut->getSize(); ++j) { Vec2i currPos = pos + Vec2i(i, j); if(isInside(currPos) == true) { Cell *unitCell = getCell(currPos); if(unitCell == testCell) { return true; } } } } return false; } //put a units into the cells void Map::putUnitCells(Unit *unit, const Vec2i &pos) { assert(unit!=NULL); if(unit == NULL) { throw runtime_error("ut == NULL"); } const UnitType *ut= unit->getType(); for(int i = 0; i < ut->getSize(); ++i) { for(int j = 0; j < ut->getSize(); ++j) { Vec2i currPos= pos + Vec2i(i, j); assert(isInside(currPos)); if(isInside(currPos) == false) { throw runtime_error("isInside(currPos) == false"); } if( ut->hasCellMap() == false || ut->getCellMapCell(i, j, unit->getModelFacing())) { // NOT SURE UNDER WHAT CONDITIONS THIS COULD HAPPEN? assert(getCell(currPos)->getUnit(unit->getCurrField()) == NULL); if(getCell(currPos)->getUnit(unit->getCurrField()) != NULL) { // throw runtime_error("getCell(currPos)->getUnit(unit->getCurrField()) != NULL"); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] ERROR [getCell(currPos)->getUnit(unit->getCurrField()) != NULL] currPos [%s] unit [%s] cell unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,currPos.getString().c_str(),unit->toString().c_str(),getCell(currPos)->getUnit(unit->getCurrField())->toString().c_str()); } getCell(currPos)->setUnit(unit->getCurrField(), unit); //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] currPos = %s unit = %s\n",__FILE__,__FUNCTION__,__LINE__,currPos.getString().c_str(),unit->toString().c_str()); } else if(ut->hasCellMap() == true && ut->getAllowEmptyCellMap() == true && ut->hasEmptyCellMap() == true) { getCell(currPos)->setUnitWithEmptyCellMap(unit->getCurrField(), unit); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] currPos = %s unit = %s\n",__FILE__,__FUNCTION__,__LINE__,currPos.getString().c_str(),unit->toString().c_str()); } } } unit->setPos(pos); } //removes a unit from cells void Map::clearUnitCells(Unit *unit, const Vec2i &pos) { assert(unit!=NULL); if(unit == NULL) { throw runtime_error("unit == NULL"); } const UnitType *ut= unit->getType(); for(int i=0; igetSize(); ++i){ for(int j=0; jgetSize(); ++j){ Vec2i currPos= pos + Vec2i(i, j); assert(isInside(currPos)); if(isInside(currPos) == false) { throw runtime_error("isInside(currPos) == false"); } if(ut->hasCellMap() == false || ut->getCellMapCell(i, j, unit->getModelFacing())) { // This seems to be a bad assert since you can clear the cell // for many reasons including a unit dieing. assert(getCell(currPos)->getUnit(unit->getCurrField())==unit); if(getCell(currPos)->getUnit(unit->getCurrField()) != unit) { // throw runtime_error("getCell(currPos)->getUnit(unit->getCurrField()) != unit"); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] ERROR [getCell(currPos)->getUnit(unit->getCurrField()) != unit] currPos [%s] unit [%s] cell unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,currPos.getString().c_str(),unit->toString().c_str(),(getCell(currPos)->getUnit(unit->getCurrField()) != NULL ? getCell(currPos)->getUnit(unit->getCurrField())->toString().c_str() : "NULL")); } getCell(currPos)->setUnit(unit->getCurrField(), NULL); //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] currPos = %s unit = %s\n",__FILE__,__FUNCTION__,__LINE__,currPos.getString().c_str(),unit->toString().c_str()); } else if(ut->hasCellMap() == true && ut->getAllowEmptyCellMap() == true && ut->hasEmptyCellMap() == true) { getCell(currPos)->setUnitWithEmptyCellMap(unit->getCurrField(), NULL); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] currPos = %s unit = %s\n",__FILE__,__FUNCTION__,__LINE__,currPos.getString().c_str(),unit->toString().c_str()); } } } } // ==================== misc ==================== //return if unit is next to pos bool Map::isNextTo(const Vec2i &pos, const Unit *unit) const { for(int i=-1; i<=1; ++i) { for(int j=-1; j<=1; ++j) { if(isInside(pos.x+i, pos.y+j)) { if(getCell(pos.x+i, pos.y+j)->getUnit(fLand) == unit) { return true; } else if(getCell(pos.x+i, pos.y+j)->getUnitWithEmptyCellMap(fLand) == unit) { return true; } } } } return false; } //return if unit is next to pos bool Map::isNextTo(const Vec2i &pos, const Vec2i &nextToPos) const { for(int i=-1; i<=1; ++i) { for(int j=-1; j<=1; ++j) { if(isInside(pos.x+i, pos.y+j)) { if(getCell(pos.x+i, pos.y+j) == getCell(nextToPos.x,nextToPos.y)) { return true; } } } } return false; } void Map::clampPos(Vec2i &pos) const{ if(pos.x<0){ pos.x=0; } if(pos.y<0){ pos.y=0; } if(pos.x>=w){ pos.x=w-1; } if(pos.y>=h){ pos.y=h-1; } } void Map::prepareTerrain(const Unit *unit) { Chrono chrono; chrono.start(); flatternTerrain(unit); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); computeNormals(); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); computeInterpolatedHeights(); if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); } // ==================== PRIVATE ==================== // ==================== compute ==================== void Map::flatternTerrain(const Unit *unit){ float refHeight= getSurfaceCell(toSurfCoords(unit->getCenteredPos()))->getHeight(); for(int i=-1; i<=unit->getType()->getSize(); ++i){ for(int j=-1; j<=unit->getType()->getSize(); ++j){ Vec2i pos= unit->getPos()+Vec2i(i, j); Cell *c= getCell(pos); SurfaceCell *sc= getSurfaceCell(toSurfCoords(pos)); //we change height if pos is inside world, if its free or ocupied by the currenty building if(isInside(pos) && sc->getObject()==NULL && (c->getUnit(fLand)==NULL || c->getUnit(fLand)==unit)){ sc->setHeight(refHeight); } } } } //compute normals void Map::computeNormals(){ //compute center normals for(int i=1; isetNormal( getSurfaceCell(i, j)->getVertex().normal(getSurfaceCell(i, j-1)->getVertex(), getSurfaceCell(i+1, j)->getVertex(), getSurfaceCell(i, j+1)->getVertex(), getSurfaceCell(i-1, j)->getVertex())); } } } void Map::computeInterpolatedHeights(){ for(int i=0; isetHeight(getSurfaceCell(toSurfCoords(Vec2i(i, j)))->getHeight()); } } for(int i=1; isetHeight(getSurfaceCell(i, j)->getHeight()); } else if(k!=0 && l==0){ getCell(i*cellScale+k, j*cellScale)->setHeight(( getSurfaceCell(i, j)->getHeight()+ getSurfaceCell(i+1, j)->getHeight())/2.f); } else if(l!=0 && k==0){ getCell(i*cellScale, j*cellScale+l)->setHeight(( getSurfaceCell(i, j)->getHeight()+ getSurfaceCell(i, j+1)->getHeight())/2.f); } else{ getCell(i*cellScale+k, j*cellScale+l)->setHeight(( getSurfaceCell(i, j)->getHeight()+ getSurfaceCell(i, j+1)->getHeight()+ getSurfaceCell(i+1, j)->getHeight()+ getSurfaceCell(i+1, j+1)->getHeight())/4.f); } } } } } } void Map::smoothSurface(){ float *oldHeights= new float[getSurfaceCellArraySize()]; for(int i=0; i < getSurfaceCellArraySize(); ++i) { oldHeights[i]= surfaceCells[i].getHeight(); } for(int i=1; isetHeight(height); Object *object= getSurfaceCell(i, j)->getObject(); if(object!=NULL){ object->setHeight(height); } } } delete [] oldHeights; } void Map::computeNearSubmerged(){ for(int i=0; isetNearSubmerged(anySubmerged); } } } void Map::computeCellColors(){ for(int i=0; igetHeight()*1.5f, 1.f, 1.5f); sc->setColor(Vec3f(1.0f, 1.0f, 1.0f)/factor); } else{ sc->setColor(Vec3f(1.0f, 1.0f, 1.0f)); } } } } // static string Map::getMapPath(const string &mapName, string scenarioDir, bool errorOnNotFound) { Config &config = Config::getInstance(); vector pathList = config.getPathListForType(ptMaps,scenarioDir); for(int idx = 0; idx < pathList.size(); idx++) { const string &map_path = pathList[idx]; const string mega = map_path + "/" + mapName + ".mgm"; const string glest = map_path + "/" + mapName + ".gbm"; if (fileExists(mega)) { return mega; } else if (fileExists(glest)) { return glest; } } if(errorOnNotFound == true) { throw runtime_error("Map [" + mapName + "] not found, scenarioDir [" + scenarioDir + "]"); } return ""; } // ===================================================== // class PosCircularIterator // ===================================================== PosCircularIterator::PosCircularIterator(const Map *map, const Vec2i ¢er, int radius){ this->map= map; this->radius= radius; this->center= center; pos= center - Vec2i(radius, radius); pos.x-= 1; } bool PosCircularIterator::next(){ //iterate while dont find a cell that is inside the world //and at less or equal distance that the radius do{ pos.x++; if(pos.x > center.x+radius){ pos.x= center.x-radius; pos.y++; } if(pos.y>center.y+radius) return false; } #ifdef USE_STREFLOP while(streflop::floor(pos.dist(center)) >= (radius+1) || !map->isInside(pos)); #else while(floor(pos.dist(center)) >= (radius+1) || !map->isInside(pos)); #endif //while(!(pos.dist(center) <= radius && map->isInside(pos))); return true; } const Vec2i &PosCircularIterator::getPos(){ return pos; } // ===================================================== // class PosQuadIterator // ===================================================== PosQuadIterator::PosQuadIterator(const Quad2i &quad, int step){ this->quad= quad; this->boundingRect= quad.computeBoundingRect(); this->step= step; pos= boundingRect.p[0]; --pos.x; pos.x= (pos.x/step)*step; pos.y= (pos.y/step)*step; } bool PosQuadIterator::next(){ do{ pos.x+= step; if(pos.x > boundingRect.p[1].x){ pos.x= (boundingRect.p[0].x/step)*step; pos.y+= step; } if(pos.y>boundingRect.p[1].y) return false; } while(!quad.isInside(pos)); return true; } void PosQuadIterator::skipX(){ pos.x+= step; } const Vec2i &PosQuadIterator::getPos(){ return pos; } }}//end namespace