/* // Callback Clone Functions const int SQUARE_SIZE = 8; #include <algorithm> // Stolen directly from ALCallback.cpp struct SearchOffset { int dx,dy; int qdist; // dx*dx+dy*dy }; // Stolen directly from ALCallback.cpp bool SearchOffsetComparator (const SearchOffset& a, const SearchOffset& b) { return a.qdist < b.qdist; } // Stolen directly from ALCallback.cpp const vector<SearchOffset>& GetSearchOffsetTable (int radius) { static vector <SearchOffset> searchOffsets; int size = radius*radius*4; if (size > searchOffsets.size()) { searchOffsets.resize (size); for (int y=0;y<radius*2;y++) for (int x=0;x<radius*2;x++) { SearchOffset& i = searchOffsets[y*radius*2+x]; i.dx = x-radius; i.dy = y-radius; i.qdist = i.dx*i.dx+i.dy*i.dy; } sort (searchOffsets.begin(), searchOffsets.end(), SearchOffsetComparator); } return searchOffsets; } float3 cBuilderPlacement::ClosestBuildSite(const UnitDef* ud, float3 p, float sRadius, int facing) { if (!ud) return float3(-1.0f,0.0f,0.0f); int endr = (int)(sRadius/(SQUARE_SIZE*2)); const vector<SearchOffset>& ofs = GetSearchOffsetTable (endr); for(int so=0;so<endr*endr*4;so++) { float x = p.x+ofs[so].dx*SQUARE_SIZE*2; float z = p.z+ofs[so].dy*SQUARE_SIZE*2; if( cb->CanBuildAt(ud,float3(x,0,z),facing) ) { return float3(x,0,z); } } return float3(-1.0f,0.0f,0.0f); } */ bool cBuilderPlacement::FindWeaponPlacement(UnitInfo *U, float3& position) { if( U->BuildQ->creationUD->WeaponGuardRange == 0 ) return false; if( U->BuildQ->creationUD->ud->minWaterDepth < 0 && U->BuildQ->creationUD->WeaponSeaEff.BestRange > 0 ) { int iS = G->TM->GetSectorIndex(position); if( !G->TM->sector[iS].isWater ) position = G->TM->GetClosestSector(G->TM->waterSectorType,iS)->position; return true; } int BID = -1; float3 buildPosition; for(map<int,UnitInfo*>::iterator i=G->UImmobile.begin(); i!=G->UImmobile.end(); ++i ) { buildPosition = cb->GetUnitPos(i->first); if( i->second->udr->WeaponGuardRange == 0 && int(i->second->UDefences.size()) == 0 && CanBuildAt(U,position,buildPosition) && CanBeBuiltAt(U->BuildQ->creationUD,buildPosition,i->second->udr->WeaponGuardRange) ) if( BID == -1 || position.distance2D(buildPosition) < position.distance2D(cb->GetUnitPos(BID)) ) BID = i->first; } if( BID > 0 ) { position = cb->GetUnitPos(BID); return true; } return false; }
// give move orders to units along previously generated pathToTarget void CAttackGroup::MoveAlongPath(float3& groupPosition, int numUnits) { const int maxStepsAhead = 8; int pathMaxIndex = (int) pathToTarget.size() - 1; int step1 = std::min(pathIterator + maxStepsAhead / 2, pathMaxIndex); int step2 = std::min(pathIterator + maxStepsAhead, pathMaxIndex); const float3& moveToHereFirst = pathToTarget[step1]; const float3& moveToHere = pathToTarget[step2]; // if we aren't there yet if (groupPosition.distance2D(pathToTarget[pathMaxIndex]) > GROUP_DESTINATION_SLACK) { // TODO: give a group the order instead of each unit assert(numUnits >= 0); for (unsigned int i = 0; i < (unsigned int)numUnits; i++) { CUNIT* unit = ai->GetUnit(units[i]); if (ai->cb->GetUnitDef(unit->uid) != NULL) { // TODO: when they are near target, change this so they eg. line up // while some are here and some aren't, there's also something that // should be done with the units in front that are given the same // order+shiftorder and skittle around back and forth meanwhile if // the single unit isn't there yet if ((unit->pos()).distance2D(pathToTarget[pathMaxIndex]) > UNIT_DESTINATION_SLACK) { unit->Move(moveToHereFirst); if (moveToHere != moveToHereFirst) { unit->MoveShift(moveToHere); } } } } // if group is as close as the pathiterator-indicated target // is to the end of the path, increase pathIterator pathIterator = 0; float3 endOfPathPos = pathToTarget[pathMaxIndex]; float groupDistanceToEnemy = groupPosition.distance2D(endOfPathPos); float pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos); int increment = maxStepsAhead / 2; while (groupDistanceToEnemy <= pathIteratorTargetDistanceToEnemy && pathIterator < pathMaxIndex) { pathIterator = std::min(pathIterator + increment, pathMaxIndex); pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos); } pathIterator = std::min(pathIterator, pathMaxIndex); } else { // group thinks it has arrived at the destination this->ClearTarget(); } }
float CAttackHandler::DistanceToBase(float3 pos) { float closestDistance = FLT_MAX; for(int i = 0; i < this->kMeansK; i++) { float3 mean = this->kMeansBase[i]; float distance = pos.distance2D(mean); closestDistance = min(distance, closestDistance); } return closestDistance; }
/* Removes and return the next waypoint in the multipath corresponding to given id. */ float3 CPathManager::NextWaypoint(unsigned int pathId, float3 callerPos, float minDistance, int numRetries) { SCOPED_TIMER("AI:PFS"); //0 indicate a no-path id. if(pathId == 0) return float3(-1,-1,-1); if(numRetries>4) return float3(-1,-1,-1); //Find corresponding multipath. std::map<unsigned int, MultiPath*>::iterator pi = pathMap.find(pathId); if(pi == pathMap.end()) return float3(-1,-1,-1); MultiPath* multiPath = pi->second; if(callerPos==ZeroVector){ if(!multiPath->detailedPath.path.empty()) callerPos=multiPath->detailedPath.path.back(); } //check if detailed path need bettering if(!multiPath->estimatedPath.path.empty() && (multiPath->estimatedPath.path.back().distance2D(callerPos) < MIN_DETAILED_DISTANCE * SQUARE_SIZE || multiPath->detailedPath.path.size() <= 2)){ if(!multiPath->estimatedPath2.path.empty() //if so check if estimated path also need bettering && (multiPath->estimatedPath2.path.back().distance2D(callerPos) < MIN_ESTIMATE_DISTANCE * SQUARE_SIZE || multiPath->estimatedPath.path.size() <= 2)){ Estimate2ToEstimate(*multiPath, callerPos); } if(multiPath->caller) multiPath->caller->UnBlock(); EstimateToDetailed(*multiPath, callerPos); if(multiPath->caller) multiPath->caller->Block(); } //Repeat until a waypoint distant enought are found. float3 waypoint; do { //Get next waypoint. if(multiPath->detailedPath.path.empty()) { if(multiPath->estimatedPath2.path.empty() && multiPath->estimatedPath.path.empty()) return multiPath->finalGoal; else return NextWaypoint(pathId,callerPos,minDistance,numRetries+1); } else { waypoint = multiPath->detailedPath.path.back(); multiPath->detailedPath.path.pop_back(); } } while(callerPos.distance2D(waypoint) < minDistance && waypoint != multiPath->detailedPath.pathGoal); return waypoint; }
void CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef) { UnitCategory category = ai->ut->GetCategory(builtdef); // HACK if (category >= CAT_LAST) { return; } // find this builder BuilderTracker* builderTracker = GetBuilderTracker(builder); // make sure this builder is free bool b1 = (builderTracker->taskPlanId == 0); bool b2 = (builderTracker->buildTaskId == 0); bool b3 = (builderTracker->factoryId == 0); if (!b1 || !b2 || !b3) { return; } bool existingTP = false; for (std::list<TaskPlan>::iterator i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) { if (pos.distance2D(i->pos) < 20.0f && builtdef == i->def) { // make sure there are no other TaskPlans if (!existingTP) { existingTP = true; TaskPlanAdd(&*i, builderTracker); } else { std::stringstream msg; msg << "[CUnitHandler::TaskPlanCreate()][frame=" << ai->cb->GetCurrentFrame() << "]\n"; msg << "\ttask-plan for \"" << builtdef->humanName << "\" already present"; msg << " at position <" << pos.x << ", " << pos.y << ", " << pos.z << ">\n"; ai->GetLogger()->Log(msg.str()); } } } if (!existingTP) { TaskPlan tp; tp.pos = pos; tp.def = builtdef; tp.defName = builtdef->name; tp.currentBuildPower = 0; tp.id = taskPlanCounter++; TaskPlanAdd(&tp, builderTracker); if (category == CAT_DEFENCE) ai->dm->AddDefense(pos, builtdef); TaskPlans[category].push_back(tp); } }
float3 CAttackHandler::GetClosestBaseSpot(float3 pos) { float closestDistance = FLT_MAX; int index = 0; for(int i = 0; i < this->kMeansK; i++) { float3 mean = this->kMeansBase[i]; float distance = pos.distance2D(mean); if (distance < closestDistance) { closestDistance = distance, closestDistance; index = i; } } return kMeansBase[index]; }
bool cBuilderPlacement::CanBuildAt(UnitInfo *U, const float3& position, const float3& destination) { if( U->udr->immobileType != 0 ) // A hub or factory return position.distance2D(destination) < U->ud->buildDistance; if( U->area == 0 ) // A flying unit return true; int iS = G->TM->GetSectorIndex(destination); if( U->area->sector.find(iS) != U->area->sector.end() ) return true; if( G->TM->GetClosestSector(U->area,iS)->S->position.distance2D(destination) < U->ud->buildDistance - G->TM->convertStoP ) return true; return false; }
void CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef) { int category = ai->ut->GetCategory(builtdef); // HACK if (category == -1) return; assert(category >= 0); assert(category < LASTCATEGORY); // find this builder BuilderTracker* builderTracker = GetBuilderTracker(builder); // make sure this builder is free // KLOOTNOTE: no longer use assertions // since new code for extractor upgrading // (in CBuildUp) seems to trigger them? bool b1 = (builderTracker->taskPlanId == 0); bool b2 = (builderTracker->buildTaskId == 0); bool b3 = (builderTracker->factoryId == 0); bool b4 = (builderTracker->customOrderId == 0); if (!b1 || !b2 || !b3 || !b4) { return; } bool existingtp = false; for (list<TaskPlan>::iterator i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) { if (pos.distance2D(i->pos) < 20 && builtdef == i->def) { // make sure there are no other TaskPlans assert(!existingtp); existingtp = true; TaskPlanAdd(&*i, builderTracker); } } if (!existingtp) { TaskPlan tp; tp.pos = pos; tp.def = builtdef; tp.defName = builtdef->name; tp.currentBuildPower = 0; tp.id = taskPlanCounter++; TaskPlanAdd(&tp, builderTracker); if (category == CAT_DEFENCE) ai->dm->AddDefense(pos,builtdef); TaskPlans[category].push_back(tp); } }
bool CGridManager::ValidMapPos(float3 MapPos){ bool rvalue = true; if (MapPos.z > MapDimensions.z){ rvalue = false; }else if (MapPos.x > MapDimensions.x){ rvalue=false; }else if (MapPos.z < 0){ rvalue=false; }else if (MapPos.x < 0){ rvalue=false; }else if (MapPos == UpVector){ rvalue=false; }else if (MapPos==ZeroVector){ rvalue=false; }else if(MapPos.distance2D(ZeroVector)<50){ rvalue=false; } return rvalue; }
float3 CMap::distfrom(float3 Start, float3 Target, float distance){ NLOG("CMap::distfrom"); if(!CheckFloat3(Start)){ return UpVector; } if(!CheckFloat3(Target)){ return UpVector; } float p = distance/Start.distance2D(Target); if(p < 0) p *= -1; float dx = Start.x-Target.x; if(dx < 0) dx *= -1; float dz = Start.z-Target.z; if(dz < 0) dz *= -1; dz *= p; dx *= p; float x = Target.x; if(Start.x > Target.x){ x += dx; } else{ x -= dx; } float z = Target.z; if(Start.z > Target.z){ z += dz; }else{ z -= dz; } return float3(x,0,z); }
int CAttackGroup::SelectEnemy(int numEnemies, const float3& groupPos) { int enemySelected = -1; float shortestDistanceFound = MY_FLT_MAX; float temp; for (int i = 0; i < numEnemies; i++) { // my range not considered in picking the closest one // TODO: is it air? is it cloaked? bool b1 = ((temp = groupPos.distance2D(ai->cheat->GetUnitPos(ai->unitIDs[i]))) < shortestDistanceFound); bool b2 = (ai->cheat->GetUnitDef(ai->unitIDs[i]) != NULL); bool b3 = CloakedFix(ai->unitIDs[i]); bool b4 = ai->cheat->GetUnitDef(ai->unitIDs[i])->canfly; if (b1 && b2 && b3 && !b4) { enemySelected = i; shortestDistanceFound = temp; } } return enemySelected; }
void CCoverageCell::update(std::list<CUnit*>& uncovered) { if (isVacant()) return; float newRange = ai->coverage->getCoreRange(type, unit->type); if (newRange < range) { const float3 center = getCenter(); for (std::map<int, CUnit*>::iterator it = units.begin(); it != units.end(); ) { const float3 pos = it->second->pos(); if (center.distance2D(pos) > newRange) { uncovered.push_back(it->second); it->second->unreg(*this); units.erase(it++); } else ++it; } range = newRange; } // TODO: if core is mobile then update it when position has changed }
bool CMap::CheckFloat3(float3 pos){ NLOG("CMap::CheckFloat3"); if(pos == UpVector){ //error codes return false; }else if(pos == ZeroVector){ //error codes return false; }else if(pos == float3(-1,0,0)){ //error codes return false; }else if(pos.distance2D(UpVector) <50){ // top corner!!!!! return false; }/*else if(pos.x > G->cb->GetMapWidth()*SQUARE_SIZE){ // offmap return false; }else if(pos.z > G->cb->GetMapHeight()*SQUARE_SIZE){ // offmap return false; }else if(pos.x < 0){ // offmap return false; }else if(pos.z < 0){ // offmap return false; }*/else{ return true; } }
void CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef) { int category = ai->ut->GetCategory(builtdef); // TODO: Temp hack if(category == -1) return; assert(category >= 0); assert(category < LASTCATEGORY); // Find this builder: BuilderTracker * builderTracker = GetBuilderTracker(builder); // Make shure this builder is free: assert(builderTracker->buildTaskId == 0); assert(builderTracker->taskPlanId == 0); assert(builderTracker->factoryId == 0); assert(builderTracker->customOrderId == 0); bool existingtp = false; for(list<TaskPlan>::iterator i = TaskPlans[category]->begin(); i != TaskPlans[category]->end(); i++){ if(pos.distance2D(i->pos) < 20 && builtdef == i->def){ assert(!existingtp); // Make shure there are no other TaskPlan there existingtp = true; TaskPlanAdd(&*i, builderTracker); } } if(!existingtp){ TaskPlan tp; tp.pos = pos; tp.def = builtdef; tp.currentBuildPower = 0; tp.id = taskPlanCounter++; TaskPlanAdd(&tp, builderTracker); if(category == CAT_DEFENCE) ai->dm->AddDefense(pos,builtdef); TaskPlans[category]->push_back(tp); } }
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos) { ai -> ut -> UpdateChokePointArray(); int f3multiplier = 8 * THREATRES; int Range = int(ai -> ut -> GetMaxRange(def) / f3multiplier); int bestspotx = 0; int bestspoty = 0; // L("GetDefensePos: Range: " << Range); float averagemapsize = sqrt(float(ai -> pather -> PathMapXSize*ai -> pather -> PathMapYSize)) * f3multiplier; float bestscore_fast = 0; int bestspotx_fast = 0; int bestspoty_fast = 0; ai -> math -> TimerStart(); spotFinder -> SetRadius(Range); float* sumMap = spotFinder -> GetSumMap(); // hack to find a good start { int x = (int) (builderpos.x / f3multiplier); int y = (int) (builderpos.z / f3multiplier); float fastSumMap = sumMap[y * ai -> pather -> PathMapXSize + x]; float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier); float myscore = fastSumMap/(builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai -> pather -> HeightMap[y * ai -> pather -> PathMapXSize + x] + 200) / (ai -> pather -> AverageHeight + 10)) / (ai -> tm -> ThreatAtThisPoint(spotpos)+0.01); bestscore_fast = myscore; bestspotx_fast = x; bestspoty_fast = y; // L("Starting with bestscore_fast: " << bestscore_fast); } // L("ai -> pather -> PathMapXSize: " << ai -> pather -> PathMapXSize); // L("ai -> pather -> PathMapYSize: " << ai -> pather -> PathMapYSize); // L("ai -> pather -> PathMapXSize / CACHEFACTOR: " << ai -> pather -> PathMapXSize / CACHEFACTOR); // L("ai -> pather -> PathMapYSize / CACHEFACTOR: " << ai -> pather -> PathMapYSize / CACHEFACTOR); int skipCount = 0; int testCount = 0; for (int x = 0; x < ai -> pather -> PathMapXSize / CACHEFACTOR; x++) { for (int y = 0; y < ai -> pather -> PathMapYSize / CACHEFACTOR; y++) { // L("x: " << x << ", y: " << y); CachePoint* cachePoint = spotFinder -> GetBestCachePoint(x, y); float bestScoreInThisBox = cachePoint -> maxValueInBox; // guess that this point is as good as posible // make best posible build spot (nearest to builder) float bestX = builderpos.x / f3multiplier; float bestY = builderpos.z / f3multiplier; if (bestX > x * CACHEFACTOR) { if (bestX > (x * CACHEFACTOR + CACHEFACTOR)) { bestX = x * CACHEFACTOR + CACHEFACTOR; } } else { bestX = x * CACHEFACTOR; } if (bestY > y * CACHEFACTOR) { if (bestY > (y * CACHEFACTOR + CACHEFACTOR)) { bestY = y * CACHEFACTOR + CACHEFACTOR; } } else { bestY = y * CACHEFACTOR; } // L("bestX: " << bestX << ", bestY: " << bestY); float3 bestPosibleSpotpos = float3(bestX*f3multiplier,0,bestY*f3multiplier); // this must be guessed, set it to the best posible (slow) float bestThreatAtThisPoint = 0.01 + ai -> tm -> GetAverageThreat() - 1; // L("bestThreatAtThisPoint: " << bestThreatAtThisPoint); float bestDistance = builderpos.distance2D(bestPosibleSpotpos); // L("bestDistance: " << bestDistance); // L("cachePoint -> maxValueInBox: " << cachePoint -> maxValueInBox << ", cachePoint -> x: " << cachePoint -> x << ", cachePoint -> y: " << cachePoint -> y); float bestHeight = ai -> pather -> HeightMap[cachePoint -> y * ai -> pather -> PathMapXSize + cachePoint -> x] + 200; // L("bestHeight: " << bestHeight); float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 4) * (bestHeight + 200) / bestThreatAtThisPoint; // L("bestPosibleMyScore: " << bestPosibleMyScore); // have a best posible score for all points inside the size of the cache box // if this is better than the current known best, test if any point inside the box is better // L("bestscore_fast: " << bestscore_fast); if (bestPosibleMyScore > bestscore_fast) { testCount++; // must test all the points inside this box for (int sx = x * CACHEFACTOR; sx < ai -> pather -> PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++) { for (int sy = y * CACHEFACTOR; sy < ai -> pather -> PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++) { float fastSumMap = sumMap[sy * ai -> pather -> PathMapXSize + sx]; float3 spotpos = float3(sx * f3multiplier, 0, sy * f3multiplier); float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai -> pather -> HeightMap[sy * ai -> pather -> PathMapXSize + sx]+200) / (ai -> tm -> ThreatAtThisPoint(spotpos) + 0.01); // L("Checking defense spot. fastSumMap: " << fastSumMap << ", Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai -> pather -> HeightMap[sy * ai -> pather -> PathMapXSize + sx] << " Threat " << ai -> tm -> ThreatAtThisPoint(spotpos)<< " Score: " << myscore); // THIS COULD BE REALLY SLOW! if (myscore > bestscore_fast && BuildMaskArray[sy * ai -> pather -> PathMapXSize + sx] == 0 && ai -> cb -> CanBuildAt(def, spotpos)) { bestscore_fast = myscore; bestspotx_fast = sx; bestspoty_fast = sy; // L("new bestscore_fast: " << myscore << "sx: " << sx << ", sy: " << sy); } } } } else { // L("Skiping box"); skipCount++; } } } // L("spotFinder new time:" << ai -> math -> TimerSecs()); // L("skipCount: " << skipCount << ", testCount: " << testCount); bestspotx = bestspotx_fast; bestspoty = bestspoty_fast; return float3(bestspotx * f3multiplier, 0, bestspoty * f3multiplier); }
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos, float heightK, CCoverageHandler *ch) { ai->math->StartTimer(getDefensePosTime); ai->ut->UpdateChokePointArray(); // TODO: UpdateChokePointArray() needs fixing. int f3multiplier = 8*THREATRES; int Range = int(ai->ut->GetMaxRange(def) / f3multiplier); //super hack by firenu (shouldnt happen anyway): if (Range <= 0) { L("GetDefensePos: Range was zero for a defense building: " << def->humanName); Range = 1; } int bestspotx = 0; int bestspoty = 0; L("GetDefensePos: Range: " << Range); float averagemapsize = sqrt(float(ai->pather->PathMapXSize*ai->pather->PathMapYSize)) * f3multiplier; /* ai->math->TimerStart(); spotFinder->SetRadius(Range); float* sumMap = spotFinder->GetSumMap(); for(int x = 0; x < ai->pather->PathMapXSize; x++){ for(int y = 0; y < ai->pather->PathMapYSize; y++){ float myscore = 0; for (int myx = x - Range; myx <= x + Range; myx++){ if (myx >= 0 && myx < ai->pather->PathMapXSize){ for (int myy = y - Range; myy <= y + Range; myy++){ int distance = (x - myx)*(x - myx) + (y - myy)*(y - myy);// - 0.5; if (myy >= 0 && myy < ai->pather->PathMapYSize && (distance) <= squarerange){ myscore += Chokepointmap[myy * ai->pather->PathMapXSize + myx]; } } } } // Test how large the dif is between sumMap and myscore: float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x]; float delta = fastSumMap - myscore; float errorSize = abs(delta /myscore); if(delta != 0) L("fastSumMap: " << fastSumMap << ", myscore: " << myscore << ", errorSize: " << errorSize << ", delta: " << delta); float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier); myscore = myscore/(builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[y * ai->pather->PathMapXSize + x]+200) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01); //L("Checking defense spot. Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] << " Threat " << ai->tm->ThreatAtThisPoint(spotpos)<< " Score: " << myscore); if(myscore> bestscore && ai->pather->VehicleArray[y * ai->pather->PathMapXSize + x]){ bestscore = myscore; bestspotx = x; bestspoty = y; } } } L("old:" << ai->math->TimerSecs()); */ float bestscore_fast = 0; int bestspotx_fast = 0; int bestspoty_fast = 0; ai->math->TimerStart(); spotFinder->SetRadius(Range); float* sumMap = spotFinder->GetSumMap(); // Hack to find a good start: { int x = (int) (builderpos.x / f3multiplier); int y = (int) (builderpos.z / f3multiplier); if (x<0) x=0; if (y<0) y=0; if (x>ai->pather->PathMapXSize-1) x=ai->pather->PathMapXSize-1; if (y>ai->pather->PathMapYSize-1) y=ai->pather->PathMapYSize-1; float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x]; float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier); float myscore = fastSumMap/(builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai->pather->HeightMap[y * ai->pather->PathMapXSize + x]*heightK + 200) / (ai->pather->AverageHeight + 10)) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01); bestscore_fast = myscore; bestspotx_fast = x; bestspoty_fast = y; //L("Starting with bestscore_fast: " << bestscore_fast); } //L("ai->pather->PathMapXSize: " << ai->pather->PathMapXSize); //L("ai->pather->PathMapYSize: " << ai->pather->PathMapYSize); //L("ai->pather->PathMapXSize / CACHEFACTOR: " << ai->pather->PathMapXSize / CACHEFACTOR); //L("ai->pather->PathMapYSize / CACHEFACTOR: " << ai->pather->PathMapYSize / CACHEFACTOR); int skipCount = 0; int testCount = 0; for(int x = 0; x < ai->pather->PathMapXSize / CACHEFACTOR; x++){ for(int y = 0; y < ai->pather->PathMapYSize / CACHEFACTOR; y++){ //L("x: " << x << ", y: " << y); CachePoint *cachePoint = spotFinder->GetBestCachePoint(x, y); float bestScoreInThisBox = cachePoint->maxValueInBox; // Guess that this point is as good as posible: // Make the best posible build spot (the one nearest to the builder): float bestX = builderpos.x / f3multiplier; float bestY = builderpos.z / f3multiplier; if(bestX > x * CACHEFACTOR) { if(bestX > (x * CACHEFACTOR + CACHEFACTOR)) { bestX = x * CACHEFACTOR + CACHEFACTOR; } } else { bestX = x * CACHEFACTOR; } if(bestY > y * CACHEFACTOR) { if(bestY > (y * CACHEFACTOR + CACHEFACTOR)) { bestY = y * CACHEFACTOR + CACHEFACTOR; } } else { bestY = y * CACHEFACTOR; } //L("bestX: " << bestX << ", bestY: " << bestY); float3 bestPosibleSpotpos = float3(bestX*f3multiplier,0,bestY*f3multiplier); float bestThreatAtThisPoint = 0.01 + ai->tm->GetAverageThreat() -1; // This must be guessed atm, set it to the best posible (slow) //L("bestThreatAtThisPoint: " << bestThreatAtThisPoint); float bestDistance = builderpos.distance2D(bestPosibleSpotpos); //L("bestDistance: " << bestDistance); //L("cachePoint->maxValueInBox: " << cachePoint->maxValueInBox << ", cachePoint->x: " << cachePoint->x << ", cachePoint->y: " << cachePoint->y); float bestHeight = ai->pather->HeightMap[cachePoint->y * ai->pather->PathMapXSize + cachePoint->x]*heightK + 200; // This must be guessed atm //L("bestHeight: " << bestHeight); float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 8) * (bestHeight + 200) / bestThreatAtThisPoint; //L("bestPosibleMyScore: " << bestPosibleMyScore); // Have a best posible score for all points inside the size of the cache box. // If this is better than the current known best, test if any points inside the box is better: //L("bestscore_fast: " << bestscore_fast); if(bestPosibleMyScore > bestscore_fast) { testCount++; // Must test all the points inside this box: for(int sx = x * CACHEFACTOR; sx < ai->pather->PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++){ for(int sy = y * CACHEFACTOR; sy < ai->pather->PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++){ if (ai->uh->Distance2DToNearestFactory(sx*f3multiplier,sy*f3multiplier)>DEFCBS_RADIUS) continue; if (ch && ch->GetCoverage(float3(sx*f3multiplier,0,sy*f3multiplier))!=0) continue; float fastSumMap = sumMap[sy * ai->pather->PathMapXSize + sx]; float3 spotpos = float3(sx*f3multiplier,0,sy*f3multiplier); float myscore = fastSumMap/(builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx]*heightK+200) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01); //L("Checking defense spot. fastSumMap: " << fastSumMap << ", Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx] << " Threat " << ai->tm->ThreatAtThisPoint(spotpos)<< " Score: " << myscore); if(myscore > bestscore_fast && BuildMaskArray[sy * ai->pather->PathMapXSize + sx] == 0 && ai->cb->CanBuildAt(def,spotpos)){ // COULD BE REALLY SLOW! bestscore_fast = myscore; bestspotx_fast = sx; bestspoty_fast = sy; //L("new bestscore_fast: " << myscore << "sx: " << sx << ", sy: " << sy); } } } } else { //L("Skiping box"); skipCount++; } } } L("spotFinder new time:" << ai->math->TimerSecs()); L("skipCount: " << skipCount << ", testCount: " << testCount); /* if(bestspotx_fast != bestspotx || bestspoty_fast != bestspoty || bestscore_fast != bestscore) { L("ERROR: bestscore_fast: " << bestscore_fast << ", bestscore: " << bestscore_fast); L("bestspotx_fast: " << bestspotx_fast << ", bestspotx: " << bestspotx << ", bestspoty_fast: " << bestspoty_fast << ", bestspoty: " << bestspoty ); }*/ bestspotx = bestspotx_fast; bestspoty = bestspoty_fast; /* ai->math->TimerStart(); //spotFinder->BackingArrayChanged(); spotFinder->SetRadius(Range); float* sumMap = spotFinder->GetSumMap(); //L("GetSumMap:" << ai->math->TimerSecs()); ai->math->TimerStart(); bestscore = 0; bestspotx = 0; bestspoty = 0; for(int x = 0; x < ai->pather->PathMapXSize; x++){ for(int y = 0; y < ai->pather->PathMapYSize; y++){ float myscore = sumMap[y * ai->pather->PathMapXSize + x]; float3 spotpos = float3(x*f3multiplier,0,y*f3multiplier); myscore = myscore/(builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[y * ai->pather->PathMapXSize + x]+200) / (ai->tm->ThreatAtThisPoint(spotpos)+0.01); //L("Checking defense spot. Distance: " << builderpos.distance2D(spotpos) << " Height: " << ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] << " Threat " << ai->tm->ThreatAtThisPoint(spotpos)<< " Score: " << myscore); if(myscore> bestscore && ai->pather->VehicleArray[y * ai->pather->PathMapXSize + x]){ bestscore = myscore; bestspotx = x; bestspoty = y; } } } L("spotFinder new time:" << ai->math->TimerSecs()); */ ai->math->StopTimer(getDefensePosTime); return float3(bestspotx*f3multiplier,0,bestspoty*f3multiplier); }
void CMapDamage::Explosion(const float3& pos, float strength,float radius) { if(pos.x<0 || pos.z<0 || pos.x>gs->mapx*SQUARE_SIZE || pos.z>gs->mapy*SQUARE_SIZE){ // info->AddLine("Map damage explosion outside map %.0f %.0f",pos.x,pos.z); return; } if(strength<10 || radius<8) return; radius*=1.5; Explo* e=new Explo; e->pos=pos; e->strength=strength; e->ttl=10; e->x1=max((int)(pos.x-radius)/SQUARE_SIZE,2); e->x2=min((int)(pos.x+radius)/SQUARE_SIZE,gs->mapx-3); e->y1=max((int)(pos.z-radius)/SQUARE_SIZE,2); e->y2=min((int)(pos.z+radius)/SQUARE_SIZE,gs->mapy-3); float baseStrength=-pow(strength,0.6f)*3/mapHardness; float invRadius=1.0/radius; for(int y=e->y1;y<=e->y2;++y){ for(int x=e->x1;x<=e->x2;++x){ if(readmap->groundBlockingObjectMap[y*gs->mapx+x] && readmap->groundBlockingObjectMap[y*gs->mapx+x]->blockHeightChanges){ //dont change squares with building on them here e->squares.push_back(0); continue; } float dist=pos.distance2D(float3(x*SQUARE_SIZE,0,y*SQUARE_SIZE)); //calculate the distance float relDist=dist*invRadius; //normalize distance float dif=baseStrength*craterTable[int(relDist*200)]*invHardness[readmap->typemap[(y/2)*gs->hmapx+x/2]]; float prevDif=readmap->heightmap[y*(gs->mapx+1)+x]-readmap->orgheightmap[y*(gs->mapx+1)+x]; // prevDif+=dif*5; if(prevDif*dif>0) dif/=fabs(prevDif)*0.1+1; e->squares.push_back(dif); if(dif<-0.3 && strength>200) treeDrawer->RemoveGrass(x,y); } } std::vector<CUnit*> units=qf->GetUnitsExact(pos,radius); for(std::vector<CUnit*>::iterator ui=units.begin();ui!=units.end();++ui){ //calculate how much to offset the buildings in the explosion radius with (while still keeping the ground under them flat if((*ui)->blockHeightChanges && (*ui)->isMarkedOnBlockingMap){ CUnit* unit=*ui; float3& upos=(*ui)->pos; float totalDif=0; for(int z=unit->mapPos.y; z<unit->mapPos.y+unit->ysize; z++){ for(int x=unit->mapPos.x; x<unit->mapPos.x+unit->xsize; x++){ float dist=pos.distance2D(float3(x*SQUARE_SIZE,0,z*SQUARE_SIZE)); //calculate the distance float relDist=dist*invRadius; //normalize distance float dif=baseStrength*craterTable[int(relDist*200)]*invHardness[readmap->typemap[(z/2)*gs->hmapx+x/2]]; float prevDif=readmap->heightmap[z*(gs->mapx+1)+x]-readmap->orgheightmap[z*(gs->mapx+1)+x]; if(prevDif*dif>0) dif/=fabs(prevDif)*0.1+1; totalDif+=dif; } } totalDif/=unit->xsize*unit->ysize; if(totalDif!=0){ ExploBuilding eb; eb.id=(*ui)->id; eb.dif=totalDif; eb.tx1=unit->mapPos.x; eb.tx2=unit->mapPos.x+unit->xsize; eb.tz1=unit->mapPos.y; eb.tz2=unit->mapPos.y+unit->ysize; e->buildings.push_back(eb); } } } explosions.push_back(e); readmap->Explosion(pos.x,pos.z,strength); }
void CUnitHandler::BuildTaskCreate(int id) { const UnitDef* newUnitDef = ai->cb->GetUnitDef(id); const UnitCategory category = ai->ut->GetCategory(id); const float3 pos = ai->cb->GetUnitPos(id); if ((!newUnitDef->movedata || category == CAT_DEFENCE) && !newUnitDef->canfly && category != CAT_LAST) { // this needs to change, so that it can make more stuff if (category >= CAT_LAST) { return; } BuildTask bt; bt.id = -1; std::list<TaskPlan>::iterator i; for (i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) { if (pos.distance2D(i->pos) < 1.0f && newUnitDef == i->def) { bt.category = category; bt.id = id; bt.pos = i->pos; bt.def = newUnitDef; std::list<BuilderTracker*> moveList; for (std::list<BuilderTracker*>::iterator builder = i->builderTrackers.begin(); builder != i->builderTrackers.end(); builder++) { moveList.push_back(*builder); } for (std::list<BuilderTracker*>::iterator builder = moveList.begin(); builder != moveList.end(); builder++) { TaskPlanRemove(*builder); BuildTaskAddBuilder(&bt, *builder); } // there can not be more than one found TaskPlan break; } } if (bt.id == -1) { // buildtask creation error (can happen if builder manages // to restart a dead building, or a human has taken control), // make one anyway std::stringstream msg; msg << "[CUnitHandler::BuildTaskCreate()][frame=" << ai->cb->GetCurrentFrame() << "]\n"; msg << "\tBuildTask Creation Error for task with ID " << id << "\n"; ai->GetLogger()->Log(msg.str()); if (category == CAT_DEFENCE) { ai->dm->AddDefense(pos, newUnitDef); } bt.category = category; bt.id = id; bt.pos = pos; bt.def = newUnitDef; // if we have any friendly builders for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) { BuilderTracker* builderTracker = *i; // check what builder is doing const CCommandQueue* cq = ai->cb->GetCurrentUnitCommands(builderTracker->builderID); if (!cq->empty()) { Command c = cq->front(); const bool b0 = (c.id == -newUnitDef->id && c.params[0] == pos.x && c.params[2] == pos.z); // at this pos const bool b1 = (c.id == CMD_REPAIR && c.params[0] == id); // at this unit (id) const bool b2 = (c.id == CMD_GUARD && c.params[0] == id); // at this unit (id) const bool b3 = b0 || b1 || b2; if (b3) { if (builderTracker->buildTaskId != 0) { BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId); if (buildTask->builderTrackers.size() > 1) { BuildTaskRemove(builderTracker); } else { // only builder of this thing, and now idle BuildTaskRemove(builderTracker); } } if (builderTracker->taskPlanId != 0) { GetTaskPlan(builderTracker->taskPlanId); TaskPlanRemove(builderTracker); } if (builderTracker->factoryId != 0) { FactoryBuilderRemove(builderTracker); } // this builder is now free if (builderTracker->idleStartFrame == -2) { IdleUnitRemove(builderTracker->builderID); } // add it to this task BuildTaskAddBuilder(&bt, builderTracker); msg.str(""); msg << "\tadded builder " << builderTracker->builderID << " to"; msg << " build-task with ID " << builderTracker->buildTaskId << "\n"; ai->GetLogger()->Log(msg.str()); } } } // add the task anyway BuildTasks[category].push_back(bt); } else { if (category == CAT_DEFENCE) ai->dm->AddDefense(pos,newUnitDef); BuildTasks[category].push_back(bt); } } }
void CBasicMapDamage::Explosion(const float3& pos, float strength, float radius) { if ((pos.x < 0.0f) || (pos.x > gs->mapx * SQUARE_SIZE)) { return; } if ((pos.z < 0.0f) || (pos.z > gs->mapy * SQUARE_SIZE)) { return; } if (strength < 10.0f || radius < 8.0f) { return; } radius *= 1.5f; Explo* e = new Explo; e->pos = pos; e->strength = strength; e->ttl = 10; e->x1 = std::max((int) (pos.x - radius) / SQUARE_SIZE, 2); e->x2 = std::min((int) (pos.x + radius) / SQUARE_SIZE, gs->mapx - 3); e->y1 = std::max((int) (pos.z - radius) / SQUARE_SIZE, 2); e->y2 = std::min((int) (pos.z + radius) / SQUARE_SIZE, gs->mapy - 3); e->squares.reserve((e->y2 - e->y1 + 1) * (e->x2 - e->x1 + 1)); const float* curHeightMap = readMap->GetCornerHeightMapSynced(); const float* orgHeightMap = readMap->GetOriginalHeightMapSynced(); const unsigned char* typeMap = readMap->GetTypeMapSynced(); const float baseStrength = -math::pow(strength, 0.6f) * 3 / mapHardness; const float invRadius = 1.0f / radius; for (int y = e->y1; y <= e->y2; ++y) { for (int x = e->x1; x <= e->x2; ++x) { const CSolidObject* so = groundBlockingObjectMap->GroundBlockedUnsafe(y * gs->mapx + x); // do not change squares with buildings on them here if (so && so->blockHeightChanges) { e->squares.push_back(0.0f); continue; } // calculate the distance and normalize it const float expDist = pos.distance2D(float3(x * SQUARE_SIZE, 0, y * SQUARE_SIZE)); const float relDist = std::min(1.0f, expDist * invRadius); const unsigned int tableIdx = relDist * CRATER_TABLE_SIZE; float dif = baseStrength * craterTable[tableIdx] * invHardness[typeMap[(y / 2) * gs->hmapx + x / 2]]; // FIXME: compensate for flattened ground under dead buildings const float prevDif = curHeightMap[y * gs->mapxp1 + x] - orgHeightMap[y * gs->mapxp1 + x]; if (prevDif * dif > 0.0f) { dif /= math::fabs(prevDif) * 0.1f + 1; } e->squares.push_back(dif); if (dif < -0.3f && strength > 200.0f) { treeDrawer->RemoveGrass(float3(x * SQUARE_SIZE, 0.0f, y * SQUARE_SIZE)); } } } // calculate how much to offset the buildings in the explosion radius with // (while still keeping the ground below them flat) const std::vector<CUnit*>& units = quadField->GetUnitsExact(pos, radius); for (std::vector<CUnit*>::const_iterator ui = units.begin(); ui != units.end(); ++ui) { CUnit* unit = *ui; if (!unit->blockHeightChanges) { continue; } if (!unit->IsBlocking()) { continue; } float totalDif = 0.0f; for (int z = unit->mapPos.y; z < unit->mapPos.y + unit->zsize; z++) { for (int x = unit->mapPos.x; x < unit->mapPos.x + unit->xsize; x++) { // calculate the distance and normalize it const float expDist = pos.distance2D(float3(x * SQUARE_SIZE, 0, z * SQUARE_SIZE)); const float relDist = std::min(1.0f, expDist * invRadius); const unsigned int tableIdx = relDist * CRATER_TABLE_SIZE; float dif = baseStrength * craterTable[tableIdx] * invHardness[typeMap[(z / 2) * gs->hmapx + x / 2]]; const float prevDif = curHeightMap[z * gs->mapxp1 + x] - orgHeightMap[z * gs->mapxp1 + x]; if (prevDif * dif > 0.0f) { dif /= math::fabs(prevDif) * 0.1f + 1; } totalDif += dif; } } totalDif /= (unit->xsize * unit->zsize); if (totalDif != 0.0f) { ExploBuilding eb; eb.id = (*ui)->id; eb.dif = totalDif; eb.tx1 = unit->mapPos.x; eb.tx2 = unit->mapPos.x + unit->xsize; eb.tz1 = unit->mapPos.y; eb.tz2 = unit->mapPos.y + unit->zsize; e->buildings.push_back(eb); } } explosions.push_back(e); }
float3 CDefenseMatrix::GetDefensePos(const UnitDef* def, float3 builderpos) { ai->ut->UpdateChokePointArray(); int f3multiplier = 8 * THREATRES; int Range = int(ai->ut->GetMaxRange(def) / f3multiplier); int bestspotx = 0; int bestspoty = 0; float averagemapsize = sqrt(float(ai->pather->PathMapXSize * ai->pather->PathMapYSize)) * f3multiplier; float bestscore_fast = 0.0f; int bestspotx_fast = 0; int bestspoty_fast = 0; ai->math->TimerStart(); spotFinder->SetRadius(Range); float* sumMap = spotFinder->GetSumMap(); // hack to find a good start { int x = (int) (builderpos.x / f3multiplier); int y = (int) (builderpos.z / f3multiplier); float fastSumMap = sumMap[y * ai->pather->PathMapXSize + x]; float3 spotpos = float3(x * f3multiplier, 0, y * f3multiplier); float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 8) * ((ai->pather->HeightMap[y * ai->pather->PathMapXSize + x] + 200) / (ai->pather->AverageHeight + 10)) / (ai->tm->ThreatAtThisPoint(spotpos) + 0.01); bestscore_fast = myscore; bestspotx_fast = x; bestspoty_fast = y; } int skipCount = 0; int testCount = 0; for (int x = 0; x < ai->pather->PathMapXSize / CACHEFACTOR; x++) { for (int y = 0; y < ai->pather->PathMapYSize / CACHEFACTOR; y++) { // KLOOTNOTE: SOMETIMES RETURNS UNINITIALIZED CRAP? // (gdb) print cachePoint->y $2 = 219024104 // (gdb) print cachePoint->x $3 = -1215908928 CachePoint* cachePoint = spotFinder->GetBestCachePoint(x, y); if (!cachePoint) { return ZeroVector; } float bestScoreInThisBox = cachePoint->maxValueInBox; // guess that this point is as good as posible // make best posible build spot (nearest to builder) float bestX = builderpos.x / f3multiplier; float bestY = builderpos.z / f3multiplier; if (bestX > x * CACHEFACTOR) { if (bestX > (x * CACHEFACTOR + CACHEFACTOR)) { bestX = x * CACHEFACTOR + CACHEFACTOR; } } else { bestX = x * CACHEFACTOR; } if (bestY > y * CACHEFACTOR) { if (bestY > (y * CACHEFACTOR + CACHEFACTOR)) { bestY = y * CACHEFACTOR + CACHEFACTOR; } } else { bestY = y * CACHEFACTOR; } float3 bestPosibleSpotpos = float3(bestX * f3multiplier, 0, bestY * f3multiplier); // this must be guessed, set it to the best possible (slow) float bestThreatAtThisPoint = 0.01 + ai->tm->GetAverageThreat() - 1; float bestDistance = builderpos.distance2D(bestPosibleSpotpos); float bestHeight = ai->pather->HeightMap[cachePoint->y * ai->pather->PathMapXSize + cachePoint->x] + 200; float bestPosibleMyScore = bestScoreInThisBox / (bestDistance + averagemapsize / 4) * (bestHeight + 200) / bestThreatAtThisPoint; // have a best posible score for all points inside the size of the cache box // if this is better than the current known best, test if any point inside the box is better if (bestPosibleMyScore > bestscore_fast) { testCount++; // must test all the points inside this box for (int sx = x * CACHEFACTOR; sx < ai->pather->PathMapXSize && sx < (x * CACHEFACTOR + CACHEFACTOR); sx++) { for (int sy = y * CACHEFACTOR; sy < ai->pather->PathMapYSize && sy < (y * CACHEFACTOR + CACHEFACTOR); sy++) { float fastSumMap = sumMap[sy * ai->pather->PathMapXSize + sx]; float3 spotpos = float3(sx * f3multiplier, 0, sy * f3multiplier); float myscore = fastSumMap / (builderpos.distance2D(spotpos) + averagemapsize / 4) * (ai->pather->HeightMap[sy * ai->pather->PathMapXSize + sx]+200) / (ai->tm->ThreatAtThisPoint(spotpos) + 0.01); // THIS COULD BE REALLY SLOW! if (myscore > bestscore_fast && BuildMaskArray[sy * ai->pather->PathMapXSize + sx] == 0 && ai->cb->CanBuildAt(def, spotpos)) { bestscore_fast = myscore; bestspotx_fast = sx; bestspoty_fast = sy; } } } } else { // skip box skipCount++; } } } bestspotx = bestspotx_fast; bestspoty = bestspoty_fast; return float3(bestspotx * f3multiplier, 0, bestspoty * f3multiplier); }