// called from CAttackHandler::Update() void CAttackGroup::Update(int frameNr) { int frameSpread = 30; unsigned int numUnits = units.size(); if (!numUnits) { // empty attack group, nothing to update return; } float3 groupPosition = GetGroupPos(); if (groupPosition == ERRORVECTOR) return; // this part of the code checks for nearby enemies and does focus fire/maneuvering if ((frameNr % frameSpread) == ((groupID * 4) % frameSpread)) { isShooting = false; // get all enemies within attack range float range = highestAttackRange + 100.0f; int numEnemies = ai->cheat->GetEnemyUnits(&ai->unitIDs[0], groupPosition, range); if (numEnemies > 0) { // select one of the enemies int enemySelected = SelectEnemy(numEnemies, groupPosition); // for every unit, pathfind to enemy perifery (with personal range - 10) then // if distance to that last point in the path is < 10 or cost is 0, attack if (enemySelected != -1) { AttackEnemy(enemySelected, numUnits, range, frameSpread); } } } if (pathToTarget.size() >= 2) { // AssignToTarget() was called for this group so // we have an attack position and path, just move // (movement may be slow due to spreading of orders) if (!isShooting && isMoving && (frameNr % 60 == (groupID * 5) % frameSpread)) { MoveAlongPath(groupPosition, numUnits); } } else { // find something to attack within visual and radar LOS if AssignToTarget() wasn't called if ((defending && !isShooting && !isMoving) && (frameNr % 60 == groupID % 60)) { FindDefenseTarget(groupPosition, frameNr); } } }
void CAttackGroup::Update() { int frameNr = ai->cb->GetCurrentFrame(); ////L("AG: Update-start. isShooting:" << isShooting << " isMoving:" << isMoving << " frame:" << frameNr << " groupID:" << groupID << " path size:" << pathToTarget.size()); int numUnits = (int)units.size(); if(!numUnits) { //L("updated an empty AttackGroup!"); return; } int frameSpread; // variable used as a varying "constant" for determining how often a part of the update scheme is done float3 groupPosition = this->GetGroupPos(); if(groupPosition == ERRORVECTOR) return; //debug line: // //ai->cb->CreateLineFigure(groupPosition + float3(0,100,50), groupPosition + float3(5+(unitCounter*20),100,50),20,0,2,groupID+1500); //sets the isShooting variable. - this part of the code checks for nearby enemies and does focus fire/maneuvering frameSpread = 30; if (/*myEnemy == -1 && */frameNr % frameSpread == (groupID*4) % frameSpread) { // //L("AG: isShooting start"); this->isShooting = false; // int enemies[MAXUNITS]; //get all enemies within attack range: float range = this->highestAttackRange + 100.0f;//(this->highestAttackRange+200.0f)*2.0f; int numEnemies = ai->cheat->GetEnemyUnits(unitArray, groupPosition, range); // //L("this is the isShooting setting procedure, numEnemies=" << numEnemies << " range checked: " << range << " and the position of the group is (" << groupPosition.x << " " << groupPosition.y << " " << groupPosition.z << ") numUnits:" << numUnits); //assert(numEnemies > 0); if(numEnemies > 0) { ////L("this is the isShooting setting procedure, numEnemies=" << numEnemies << " range checked: " << range << " and the position of the group is (" << groupPosition.x << " " << groupPosition.y << " " << groupPosition.z << ") numUnits:" << numUnits); // //L("this is the isShooting setting and numEnemies was more than 0 : " << numEnemies); //ai->cb->SendTextMsg("attackgroup : Im not sure that this happens, ever", 0); //selecting one of the enemies int enemySelected = -1; float shortestDistanceFound = FLT_MAX; float temp; //bool closestSoFarIsBuilding = false; shoot units first //float3 enemyPos;// = ai->cheat->GetUnitPos(enemies[enemySelected]); int xSize = 40; int lineGroupID = groupID+5000; // int heightOffset = 10; for (int i = 0; i < numEnemies; i++) { //my range not considered in picking the closest one //TODO: is it air? is it cloaked? if (((temp = groupPosition.distance2D(ai->cheat->GetUnitPos(unitArray[i]))) < shortestDistanceFound) && ai->cheat->GetUnitDef(unitArray[i]) != NULL && CloakedFix(unitArray[i]) && !ai->cheat->GetUnitDef(unitArray[i])->canfly) { enemySelected = i; shortestDistanceFound = temp; } // enemyPos = ai->cheat->GetUnitPos(unitArray[i]); // //ai->cb->CreateLineFigure(enemyPos + float3(-xSize,heightOffset,0), enemyPos + float3(xSize,heightOffset,0), 5, 0, frameSpread/2, 6000+(groupID*6000 + i)); // //ai->cb->CreateLineFigure(enemyPos + float3(0,heightOffset,-xSize), enemyPos + float3(0,heightOffset,xSize), 5, 0, frameSpread/2, 6000+(groupID*6000 + numEnemies + i)); } // enemyPos = ai->cheat->GetUnitPos(unitArray[enemySelected]); //X marks the target // //ai->cb->CreateLineFigure(enemyPos + float3(-xSize,heightOffset,-xSize), enemyPos + float3(xSize,heightOffset,xSize), 5, 0, frameSpread, lineGroupID); // //ai->cb->CreateLineFigure(enemyPos + float3(-xSize,heightOffset,xSize), enemyPos + float3(xSize,heightOffset,-xSize), 5, 0, frameSpread, lineGroupID); //tiny line from there to groupPosition // //ai->cb->CreateLineFigure(enemyPos, groupPosition, 5, 0, frameSpread, lineGroupID); //for every unit, pathfind to enemy perifery(with personal range-10) then if distance to that last point in the path is < 10 or cost is 0, attack // hack: just attack it ////L("index of the best enemy: " << enemySelected << " its distance: " << shortestDistanceFound << " its id:" << enemies[enemySelected] << " humanName:" << ai->cheat->GetUnitDef(enemies[enemySelected])->humanName); //TODO: can enemy id be 0 //GIVING ATTACK ORDER: if (enemySelected != -1) { //L("AG:isShooting: YES"); float3 enemyPos = ai->cheat->GetUnitPos(unitArray[enemySelected]); assert (CloakedFix(unitArray[enemySelected])); this->isShooting = true; for (int i = 0; i < numUnits; i++) { int unit = units[i]; //does our unit exist and its not currently maneuvering if (ai->cb->GetUnitDef(unit) != NULL && ai->MyUnits[unit]->maneuverCounter-- <= 0) { //add a routine finding the best(not just closest) target, but for now just fire away //TODO: add canattack ai->MyUnits[unit]->Attack(unitArray[enemySelected]); //TODO: some cases, force fire on position //assert(!ai->cheat->GetUnitDef(unitArray[enemySelected])->canfly); //TODO: this should be the max range of the weapon the unit has with the lowest range //assuming you want to rush in with the heavy stuff, that is assert(range >= ai->cb->GetUnitMaxRange(unit)); //SINGLE UNIT MANEUVERING: //testing the possibility of retreating to max range if target is too close float3 myPos = ai->cb->GetUnitPos(unit); float myRange = this->ai->ut->GetMaxRange(ai->cb->GetUnitDef(unit)); //is it air, or air thats landed if(!ai->cb->GetUnitDef(unit)->canfly || myPos.y < ai->cb->GetElevation(myPos.x, myPos.z) + 25 && (myRange - UNIT_MIN_MANEUVER_RANGE_DELTA) > myPos.distance2D(enemyPos)) { bool debug1 = true; bool debug2 = false; // ai->cb->SendTextMsg("range diff makes it good to maneuver && im not air", 0); vector<float3> tempPath; //two things: 1. dont need a path, just a position and 2. it should avoid other immediate friendly units and/or immediate enemy units+radius //needs to be a point ON the perifery circle, not INSIDE it - fixed //maybe include the height parameter in the search? probably not possible //TODO: OBS doesnt this mean pathing might happen every second? outer limit should be more harsh than inner float3 unitPos = ai->cheat->GetUnitPos(unitArray[enemySelected]); float dist = ai->pather->FindBestPathToRadius(&tempPath, &myPos, myRange, &unitPos); if (tempPath.size() > 0) { float3 moveHere = tempPath.back(); dist = myPos.distance2D(moveHere); //TODO: penetrators are now broken. kind of. //is the position between the proposed destination and the enemy higher than the average of mine and his height? bool losHack = ((moveHere.y + enemyPos.y)/2.0f) + UNIT_MAX_MANEUVER_HEIGHT_DIFFERENCE_UP > ai->cb->GetElevation((moveHere.x+enemyPos.x)/2, (moveHere.z+enemyPos.z)/2); //im here assuming the pathfinder returns correct Y values if (dist > max((UNIT_MIN_MANEUVER_RANGE_PERCENTAGE*myRange), float(UNIT_MIN_MANEUVER_DISTANCE)) && losHack) { //(enemyPos.y - moveHere.y) < UNIT_MAX_MANEUVER_HEIGHT_DIFFERENCE_UP) { debug2 = true; //ai->cb->SendTextMsg("AG: maneuvering", 0); //Draw where it would move: //ai->cb->CreateLineFigure(myPos, moveHere, 80, 1, frameSpread, RANDINT%1000000); ai->MyUnits[unit]->maneuverCounter = int(ceilf(max((float)UNIT_MIN_MANEUVER_TIME/frameSpread, (dist/ai->MyUnits[unit]->def()->speed)))); //L("AG maneuver debug, maneuverCounter set to " << ai->MyUnits[unit]->maneuverCounter << " and dist:" << dist << " speed:" << ai->MyUnits[unit]->def()->speed << " frameSpread:" << frameSpread << " dist/speed:" << (dist/ai->MyUnits[unit]->def()->speed) << " its a " << ai->MyUnits[unit]->def()->humanName); ai->MyUnits[unit]->Move(moveHere); //REMEMBER that this will suck for planes (which is why i wont add them to this group) } } if (debug1 && !debug2) { //L("AG: maneuver: pathfinder run but path not used"); } } else if (!ai->cb->GetUnitDef(unit)->canfly || myPos.y < ai->cb->GetElevation(myPos.x, myPos.z) + 25){ //L("AttackGroup: this unit is an air unit: " << ai->cb->GetUnitDef(unit)->humanName); }//endif our unit exists && we arent currently maneuvering } else { ////L("isShooting: OUR unit is dead. or something. Shouldnt happen ever. or maneuvering."); } //if cant attack, stop with the others, assuming someone was able to attack something } } } // //L("AG: isShooting end"); } if (frameNr % 30 == 0 && !defending) { //drawing the target region: //L("AG update: drawing target region (attacking)"); int heightOffset = 50; vector<float3> circleHack; float diagonalHack = attackRadius * (2.0f/3.0f); circleHack.resize(8, attackPosition); circleHack[0] += float3(-diagonalHack,heightOffset,-diagonalHack); circleHack[1] += float3(0,heightOffset,-attackRadius); circleHack[2] += float3(diagonalHack,heightOffset,-diagonalHack); circleHack[3] += float3(attackRadius,heightOffset,0); circleHack[4] += float3(diagonalHack,heightOffset,diagonalHack); circleHack[5] += float3(0,heightOffset,attackRadius); circleHack[6] += float3(-diagonalHack,heightOffset,diagonalHack); circleHack[7] += float3(-attackRadius,heightOffset,0); for(int i = 0; i < 8; i++) { //ai->cb->CreateLineFigure(circleHack[i], circleHack[(i+1)%8], 5, 0, 300, GetGroupID()+6000); } //from pos to circle center //ai->cb->CreateLineFigure(groupPosition+float3(0,heightOffset,0), attackPosition+float3(0,heightOffset,0), 5, 1, 30, GetGroupID()+6000); ai->cb->SetFigureColor(GetGroupID() + 6000, 0, 0, 0, 1.0f); //L("AG update: done drawing stuff"); } //TODO: if arrived and not isShooting, set defending? already done in ismoving-end if (defending && !isShooting && !isMoving && frameNr % 60 == groupID % 60) { FindDefenseTarget(groupPosition); } // GIVE MOVE ORDERS TO UNITS ALONG PATHTOTARGET frameSpread = 60; if (!isShooting && isMoving && frameNr % frameSpread == (groupID*5) % frameSpread) { //L("AG: start of move order part before loop"); //do the moving const int maxStepsAhead = 8; int pathMaxIndex = (int)pathToTarget.size()-1; int step1 = min(this->pathIterator + maxStepsAhead/2, pathMaxIndex); int step2 = min(this->pathIterator + maxStepsAhead, pathMaxIndex); //L("AG: picking stuff out of pathToTarget"); //L("AG: pathtotarget size: " << pathToTarget.size()); float3 moveToHereFirst = this->pathToTarget[step1]; float3 moveToHere = this->pathToTarget[step2]; //drawing destination // //ai->cb->CreateLineFigure(groupPosition + float3(0,50,0), pathToTarget[pathMaxIndex] + float3(0,50,0),8,1,frameSpread,groupID+1200); //L("AG: move order still before loop"); //if we aint there yet if (groupPosition.distance2D(pathToTarget[pathMaxIndex]) > GROUP_DESTINATION_SLACK) { for(int i = 0; i < numUnits;i++) { int unit = units[i]; if (ai->cb->GetUnitDef(unit) != NULL) { //TODO: when they are near target, change this so they line up or something while some are here and some arent. attack checker will take over soon. //theres 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 (groupPosition.distance2D(ai->cheat->GetUnitPos(myEnemy)) > this->highestAttackRange) { //if the single unit aint there yet if (ai->cb->GetUnitPos(unit).distance2D(pathToTarget[pathMaxIndex]) > UNIT_DESTINATION_SLACK) { ai->MyUnits[unit]->Move(moveToHereFirst); // //ai->cb->CreateLineFigure(ai->cb->GetUnitPos(unit) + float3(0,50,0), moveToHereFirst + float3(0,50,0),15,1,10,groupID+50000); if (moveToHere != moveToHereFirst) { ai->MyUnits[unit]->MoveShift(moveToHere); // //ai->cb->CreateLineFigure(moveToHereFirst + float3(0,50,0), moveToHere + float3(0,50,0),15,1,10,groupID+50000); } //TODO: give a spring group the order instead of each unit //draw thin line from unit to groupPos //ai->cb->CreateLineFigure(ai->cb->GetUnitPos(unit) + float3(0,50,0), groupPosition + float3(0,50,0),4,0,frameSpread,groupID+500); } else { AIHCAddMapPoint amp; amp.label = "case-sua"; amp.pos = groupPosition; // //ai->cb->HandleCommand(&); } } } //if group is as close as the pathiterator-indicated target is to the end of the path, increase pathIterator //L("AG: after move order, about to adjust stuff"); /* float3 endOfPathPos = pathToTarget[pathMaxIndex]; float groupDistanceToEnemy = groupPosition.distance2D(endOfPathPos); float pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos); if (groupDistanceToEnemy <= pathIteratorTargetDistanceToEnemy) { this->pathIterator = min(pathIterator + maxStepsAhead/2, pathMaxIndex); } if (groupDistanceToEnemy > (pathIteratorTargetDistanceToEnemy*3.0f)) { //L("AG: path iterator reset bug thing"); //this->pathIterator = min(pathIterator + maxStepsAhead/2, pathMaxIndex); this->pathIterator = 1; } */ 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 = min(pathIterator + increment, pathMaxIndex); pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos); } pathIterator = min(pathIterator, pathMaxIndex); } else { //L("AG: group thinks it has arrived at the destination:" << groupID); // AIHCAddMapPoint amp; // amp.label = "group thinks it has arrived at the destination."; // amp.pos = groupPosition; // //ai->cb->HandleCommand(&); this->ClearTarget(); } //L("AG: done updating move stuff (yay)"); }//endif move //stuck fix stuff. disabled because the spring one works now and thats not taken into consideration yet. frameSpread = 60; if (false && isMoving && !isShooting && frameNr % frameSpread == 0) { //L("AG: unit stuck checking start"); //stuck unit counter update. (at a 60 frame modulo) //TODO: if one unit has completed the path, it wont be given any new orders, but this will still happen //so there might be false positives here :< for (vector<int>::iterator it = units.begin(); it != units.end(); it++) { int unit = *it; if (ai->cb->GetUnitDef(unit)){ CUNIT *u = ai->MyUnits[unit]; float distanceMovedSinceLastUpdate = ai->cb->GetUnitPos(unit).distance2D(u->earlierPosition); if (distanceMovedSinceLastUpdate < UNIT_STUCK_MOVE_DISTANCE) { u->stuckCounter++; } else { //it moved so it isnt stuck u->stuckCounter = 0; } u->earlierPosition = u->pos(); //hack for slight maneuvering around buildings, spring fails at this sometimes if (u->stuckCounter == UNIT_STUCK_COUNTER_MANEUVER_LIMIT) { //L("AG: attempting unit unstuck manuevering for " << unit << " at pos " << u->pos().x << " " << u->pos().y << " " << u->pos().z); AIHCAddMapPoint amp; amp.label = "stuck-fix"; amp.pos = u->pos(); //ai->cb->HandleCommand(&); //findbestpath to perifery of circle around mypos, distance 2x resolution or somesuch //dont reset counter, that would make it loop manuever attempts. vector<float3> tempPath; float3 upos = u->pos(); float dist = ai->pather->FindBestPathToRadius(&tempPath, &upos, UNIT_STUCK_MANEUVER_DISTANCE, &upos); //500 = hack //float dist = ai->pather->FindBestPathToRadius(&tempPath, &ai->cb->GetUnitPos(unit), myRange, &ai->cheat->GetUnitPos(enemies[enemySelected])); if (tempPath.size() > 0) { float3 moveHere = tempPath.back(); //ai->cb->CreateLineFigure(u->pos(), moveHere, 14, 1, frameSpread, RANDINT%1000000); u->Move(moveHere); } } } }//endfor unstuck } }
void CAttackGroup::Update() { int frameNr = ai -> cb -> GetCurrentFrame(); // L("AG: Update-start. isShooting:" << isShooting << " isMoving:" << isMoving << " frame:" << frameNr << " groupID:" << groupID << " path size:" << pathToTarget.size()); // variable used as a varying "constant" for determining how often a part of the update scheme is done int frameSpread = 30; unsigned int numUnits = units.size(); if (!numUnits) { // L("updated an empty AttackGroup!"); return; } float3 groupPosition = this -> GetGroupPos(); if (groupPosition == ERRORVECTOR) return; // this part of the code checks for nearby enemies and does focus fire/maneuvering if ((frameNr % frameSpread) == ((groupID * 4) % frameSpread)) { // L("AG: isShooting start"); this -> isShooting = false; // get all enemies within attack range: float range = this -> highestAttackRange + 100.0f; int numEnemies = ai -> cheat -> GetEnemyUnits(unitArray, groupPosition, range); // L("this is the isShooting setting procedure, numEnemies=" << numEnemies << " range checked: " << range << " and the position of the group is (" << groupPosition.x << " " << groupPosition.y << " " << groupPosition.z << ") numUnits:" << numUnits); if (numEnemies > 0) { // L("this is the isShooting setting procedure, numEnemies=" << numEnemies << " range checked: " << range << " and the position of the group is (" << groupPosition.x << " " << groupPosition.y << " " << groupPosition.z << ") numUnits:" << numUnits); // L("this is the isShooting setting and numEnemies was more than 0 : " << numEnemies); // selecting one of the enemies int enemySelected = -1; float shortestDistanceFound = 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 = groupPosition.distance2D(ai -> cheat -> GetUnitPos(unitArray[i]))) < shortestDistanceFound); bool b2 = ai -> cheat -> GetUnitDef(unitArray[i]) != NULL; bool b3 = CloakedFix(unitArray[i]); bool b4 = ai -> cheat -> GetUnitDef(unitArray[i]) -> canfly; if (b1 && b2 && b3 && !b4) { enemySelected = i; shortestDistanceFound = temp; } } // for every unit, pathfind to enemy perifery (with personal range - 10) then if distance to that last point in the path is < 10 or cost is 0, attack // L("index of the best enemy: " << enemySelected << " its distance: " << shortestDistanceFound << " its id:" << enemies[enemySelected] << " humanName:" << ai -> cheat -> GetUnitDef(enemies[enemySelected]) -> humanName); // TODO: can enemy id be 0 if (enemySelected != -1) { // L("AG:isShooting: YES"); float3 enemyPos = ai -> cheat -> GetUnitPos(unitArray[enemySelected]); assert(CloakedFix(unitArray[enemySelected])); this -> isShooting = true; for (unsigned int i = 0; i < numUnits; i++) { int unit = units[i]; // does our unit exist and is it not currently maneuvering? if ((ai -> cb -> GetUnitDef(unit) != NULL) && (ai -> MyUnits[unit] -> maneuverCounter-- <= 0)) { // TODO: add a routine finding the best(not just closest) target, but for now just fire away // TODO: some cases, force fire on position // TODO: add canattack ai -> MyUnits[unit] -> Attack(unitArray[enemySelected]); // TODO: this should be the max range of the weapon the unit has with the lowest range // assuming you want to rush in with the heavy stuff, that is assert(range >= ai -> cb -> GetUnitMaxRange(unit)); // SINGLE UNIT MANEUVERING: testing the possibility of retreating to max range if target is too close float3 myPos = ai -> cb -> GetUnitPos(unit); float myRange = this -> ai -> ut -> GetMaxRange(ai -> cb -> GetUnitDef(unit)); bool b5 = ai -> cb -> GetUnitDef(unit) -> canfly; bool b6 = myPos.y < (ai -> cb -> GetElevation(myPos.x, myPos.z) + 25); bool b7 = (myRange - UNIT_MIN_MANEUVER_RANGE_DELTA) > myPos.distance2D(enemyPos); // is it air, or air that's landed if (!b5 || b6 && b7) { bool debug1 = true; bool debug2 = false; vector<float3> tempPath; // two things: 1. don't need a path, just a position and 2. it should avoid other immediate friendly units and/or immediate enemy units+radius // maybe include the height parameter in the search? probably not possible // TODO: OBS doesn't this mean pathing might happen every second? outer limit should be more harsh than inner float3 unitPos = ai -> cheat -> GetUnitPos(unitArray[enemySelected]); float dist = ai -> pather -> FindBestPathToRadius(&tempPath, &myPos, myRange, &unitPos); if (tempPath.size() > 0) { float3 moveHere = tempPath.back(); dist = myPos.distance2D(moveHere); // TODO: penetrators are now broken. kind of. // is the position between the proposed destination and the enemy higher than the average of mine and his height? float v1 = ((moveHere.y + enemyPos.y) / 2.0f) + UNIT_MAX_MANEUVER_HEIGHT_DIFFERENCE_UP; float v2 = ai -> cb -> GetElevation((moveHere.x + enemyPos.x) / 2, (moveHere.z + enemyPos.z) / 2); bool losHack = v1 > v2; // assume the pathfinder returns correct Y values // REMEMBER that this will suck for planes if (dist > max((UNIT_MIN_MANEUVER_RANGE_PERCENTAGE * myRange), float(UNIT_MIN_MANEUVER_DISTANCE)) && losHack) { debug2 = true; ai -> MyUnits[unit] -> maneuverCounter = int(ceilf(max((float) UNIT_MIN_MANEUVER_TIME / frameSpread, (dist / ai -> MyUnits[unit] -> def() -> speed)))); ai -> MyUnits[unit] -> Move(moveHere); } } if (debug1 && !debug2) { // L("AG: maneuver: pathfinder run but path not used"); } } else if (!ai -> cb -> GetUnitDef(unit) -> canfly || myPos.y < (ai -> cb -> GetElevation(myPos.x, myPos.z) + 25)) { // L("AttackGroup: this unit is an air unit: " << ai -> cb -> GetUnitDef(unit) -> humanName); } } else { // L("isShooting: OUR unit is dead. or something. Shouldnt happen ever. or maneuvering."); } // if cant attack, stop with the others, assuming someone was able to attack something } } } } if (frameNr % 30 == 0 && !defending) { // L("AG update: drawing target region (attacking)"); int heightOffset = 50; vector<float3> circleHack; float diagonalHack = attackRadius * (2.0f / 3.0f); circleHack.resize(8, attackPosition); circleHack[0] += float3(-diagonalHack, heightOffset, -diagonalHack); circleHack[1] += float3(0, heightOffset, -attackRadius); circleHack[2] += float3(diagonalHack, heightOffset, -diagonalHack); circleHack[3] += float3(attackRadius, heightOffset, 0); circleHack[4] += float3(diagonalHack, heightOffset, diagonalHack); circleHack[5] += float3(0, heightOffset, attackRadius); circleHack[6] += float3(-diagonalHack, heightOffset, diagonalHack); circleHack[7] += float3(-attackRadius, heightOffset, 0); // from pos to circle center ai -> cb -> SetFigureColor(GetGroupID() + 6000, 0, 0, 0, 1.0f); // L("AG update: done drawing stuff"); } if ((defending && !isShooting && !isMoving) && (frameNr % 60 == groupID % 60)) { FindDefenseTarget(groupPosition); } // GIVE MOVE ORDERS TO UNITS ALONG PATHTOTARGET frameSpread = 60; if (!isShooting && isMoving && (frameNr % frameSpread == (groupID * 5) % frameSpread)) { // L("AG: start of move order part before loop"); const int maxStepsAhead = 8; int pathMaxIndex = (int) pathToTarget.size() - 1; int step1 = min(this -> pathIterator + maxStepsAhead / 2, pathMaxIndex); int step2 = min(this -> pathIterator + maxStepsAhead, pathMaxIndex); // L("AG: picking stuff out of pathToTarget"); // L("AG: pathtotarget size: " << pathToTarget.size()); float3 moveToHereFirst = this -> pathToTarget[step1]; float3 moveToHere = this -> pathToTarget[step2]; // if we aren't there yet if (groupPosition.distance2D(pathToTarget[pathMaxIndex]) > GROUP_DESTINATION_SLACK) { for (unsigned int i = 0; i < numUnits; i++) { int unit = units[i]; if (ai -> cb -> GetUnitDef(unit) != NULL) { // TODO: when they are near target, change this so they line up or something while some are here and some arent. attack checker will take over soon. // theres 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 (ai -> cb -> GetUnitPos(unit).distance2D(pathToTarget[pathMaxIndex]) > UNIT_DESTINATION_SLACK) { ai -> MyUnits[unit] -> Move(moveToHereFirst); if (moveToHere != moveToHereFirst) { ai -> MyUnits[unit] -> MoveShift(moveToHere); } // TODO: give a spring group the order instead of each unit } else { AIHCAddMapPoint amp; amp.label = "case-sua"; amp.pos = groupPosition; } } } // if group is as close as the pathiterator-indicated target is to the end of the path, increase pathIterator // L("AG: after move order, about to adjust stuff"); 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 = min(pathIterator + increment, pathMaxIndex); pathIteratorTargetDistanceToEnemy = pathToTarget[pathIterator].distance2D(endOfPathPos); } pathIterator = min(pathIterator, pathMaxIndex); } else { // L("AG: group thinks it has arrived at the destination:" << groupID); this -> ClearTarget(); } // L("AG: done updating move stuff"); } // stuck fix stuff. disabled because the spring one works now and that's not taken into consideration yet. frameSpread = 60; if ((false && isMoving && !isShooting) && (frameNr % frameSpread == 0)) { // L("AG: unit stuck checking start"); // stuck unit counter update. (at a 60 frame modulo) // TODO: if one unit has completed the path, it won't be given any new orders, but this will still happen // so there might be false positives here for (vector<int>::iterator it = units.begin(); it != units.end(); it++) { int unit = *it; if (ai -> cb -> GetUnitDef(unit)) { CUNIT* u = ai -> MyUnits[unit]; float distanceMovedSinceLastUpdate = ai -> cb -> GetUnitPos(unit).distance2D(u -> earlierPosition); if (distanceMovedSinceLastUpdate < UNIT_STUCK_MOVE_DISTANCE) { u -> stuckCounter++; } else { // it moved so it isn't stuck u -> stuckCounter = 0; } u -> earlierPosition = u -> pos(); // hack for slight maneuvering around buildings, spring fails at this sometimes if (u -> stuckCounter == UNIT_STUCK_COUNTER_MANEUVER_LIMIT) { // L("AG: attempting unit unstuck manuevering for " << unit << " at pos " << u -> pos().x << " " << u -> pos().y << " " << u -> pos().z); AIHCAddMapPoint amp; amp.label = "stuck-fix"; amp.pos = u -> pos(); // findbestpath to perifery of circle around mypos, distance 2x resolution or somesuch // don't reset counter, that would make it loop manuever attempts. vector<float3> tempPath; float3 upos = u -> pos(); if (tempPath.size() > 0) { float3 moveHere = tempPath.back(); u -> Move(moveHere); } } } } } }