CDiagramEntity* CGumpRadio::Clone() { CGumpRadio* obj = new CGumpRadio(m_pGump[NORMAL],m_pGump[CHECKED], GetGroupID(), IsChecked()); obj->Copy( this ); return obj; }
void SQRCheckButton::SetCheck( bool bCheck ) { m_bCheck = bCheck; //单选框,同时只有一个可被选中 if( m_bCheck && (GetStyle() & BTN_RADIO) && GetGroupID() >= 0 ) { SQRWnd* pBrother = GetFirstBrother(); while( pBrother ) { if( GetClassName() == pBrother->GetClassName() && pBrother != this && GetGroupID() == static_cast<SQRCheckButton*>(pBrother)->GetGroupID() ) static_cast<SQRCheckButton*>(pBrother)->SetCheck( false ); pBrother = pBrother->FindNextWnd(); } } OnCheck( m_bCheck ); }
bool TBRadioCheckBox::OnEvent(const TBWidgetEvent &ev) { if (ev.target == this && ev.type == EVENT_TYPE_CLICK) { // Toggle the value, if it's not a grouped widget with value on. if (!(GetGroupID() && GetValue())) { SetValue(!GetValue()); } } return false; }
CString CGumpRadio::GetString(BOOL bBegin) const { CString ret, str; if (bBegin) { ret += CGumpCheckbox::GetString(TRUE) + "\n"; str.Format(" <group>%d</group>", GetGroupID()); ret += str; } else { ret += CGumpCheckbox::GetString(FALSE); } return ret; }
void TBRadioCheckBox::SetValue(int value) { if (m_value == value) return; m_value = value; SetState(WIDGET_STATE_SELECTED, value ? true : false); TBWidgetEvent ev(EVENT_TYPE_CHANGED); InvokeEvent(ev); if (value && GetGroupID()) UpdateGroupWidgets(this); }
void TBButton::SetValue(int value) { if (value == GetValue()) return; SetState(WIDGET_STATE_PRESSED, value ? true : false); if (CanToggle()) { // Invoke a changed event. TBWidgetEvent ev(EVENT_TYPE_CHANGED); InvokeEvent(ev); } if (value && GetGroupID()) TBRadioCheckBox::UpdateGroupWidgets(this); }
bool TBButton::OnEvent(const TBWidgetEvent &ev) { if (CanToggle() && ev.type == EVENT_TYPE_CLICK && ev.target == this) { TBWidgetSafePointer this_widget(this); // Toggle the value, if it's not a grouped widget with value on. if (!(GetGroupID() && GetValue())) SetValue(!GetValue()); if (!this_widget.Get()) return true; // We got removed so we actually handled this event. // Intentionally don't return true for this event. We want it to continue propagating. } return TBWidget::OnEvent(ev); }
void TBRadioCheckBox::SetValue(int value) { if (m_value == value) return; m_value = value; SetState(WIDGET_STATE_SELECTED, value ? true : false); Invalidate(); TBWidgetEvent ev(EVENT_TYPE_CHANGED); InvokeEvent(ev); if (!value || !GetGroupID()) return; // Toggle all other widgets in the same group. First get a root widget // for the search. TBWidget *group = this; while (group && !group->GetIsGroupRoot()) group = group->GetParent(); if (group) { ToggleGroup(group, this); } }
LandsideIntersectLinkGroupInSim* LandsideIntersectLaneLinkInSim::getGroup() const { return mpParent->GetLinkGroupById(GetGroupID()); }
//========================================================================================================= bool GetASICInfo(ASICInfo& rASICInfo) { if (nullptr == oglUtils::_oglGetPerfMonitorCountersAMD || nullptr == oglUtils::_oglGetPerfMonitorGroupStringAMD || nullptr == oglUtils::_oglGetPerfMonitorCounterInfoAMD || nullptr == oglUtils::_oglGetPerfMonitorCounterStringAMD || nullptr == oglUtils::_oglGenPerfMonitorsAMD || nullptr == oglUtils::_oglDeletePerfMonitorsAMD || nullptr == oglUtils::_oglSelectPerfMonitorCountersAMD || nullptr == oglUtils::_oglBeginPerfMonitorAMD || nullptr == oglUtils::_oglEndPerfMonitorAMD || nullptr == oglUtils::_oglGetPerfMonitorCounterDataAMD) { // No AMD_peformance_monitor support, means no ASIC info GPA_LogError("One or more of the GL_AMD_performance_monitor functions were not found."); return false; } // Find the ASIC info group (GPIN = GPu INformation) GLint nASICGroupId = GetGroupID(ASIC_GROUP); if (nASICGroupId == -1) { GPA_LogError("Unable to find the GPIN group."); return false; } // Get the ASIC ID GLuint nAsicType = 0; if (!GetCounterValue(nASICGroupId, ASIC_TYPE, nAsicType)) { GPA_LogError("Unable to get the asic id."); return false; } // query the driver version so that we can correct the asic ID after a driver // change that happened for 10.2, where support for pre-R6xx hardware was removed //(legacy driver will support that) #ifndef GLES // Since GL ES didn't exist before version 9551, there's no need to check the // version number. For now, it is assumed the version number will be >9551 const GLubyte* pVersion = oglUtils::_oglGetString(GL_VERSION); int nVersion = extractVersionNumber(pVersion); std::stringstream message; message << "ASIC ID returned from driver is: " << nAsicType << " and GL_VERSION is: " << reinterpret_cast<const char*>(pVersion) << "."; GPA_LogMessage(message.str().c_str()); #else int nVersion = INT_MAX; #endif if (nVersion < 13452) { // pre-GCN devices were removed from the driver starting with version 13452. // if the driver version is earlier than that we will return an error. GPA_LogError("OpenGL driver version is too old. Please update your driver."); return false; } // store the Asic Revision ID rASICInfo.eAsicRev = (ATIAsicID) nAsicType; // Decode the ASIC Type if (nAsicType == ATIASIC_ID_TAHITI_P || nAsicType == ATIASIC_ID_PITCAIRN_PM || nAsicType == ATIASIC_ID_CAPEVERDE_M || nAsicType == ATIASIC_ID_OLAND_M || nAsicType == ATIASIC_ID_HAINAN_M) { GPA_LogMessage("Recognized a GFX6 card."); rASICInfo.eAsicType = ASIC_Gfx6; } else if (nAsicType == ATIASIC_ID_BONAIRE_M || nAsicType == ATIASIC_ID_HAWAII_P) { GPA_LogMessage("Recognized a GFX7 card."); rASICInfo.eAsicType = ASIC_Gfx7; } else if (nAsicType == ATIASIC_ID_KALINDI || nAsicType == ATIASIC_ID_GODAVARI || nAsicType == ATIASIC_ID_SPECTRE || nAsicType == ATIASIC_ID_SPOOKY) { GPA_LogMessage("Recognized an APU with GFX7 graphics."); rASICInfo.eAsicType = ASIC_Gfx7; } else if (nAsicType == ATIASIC_ID_ICELAND_M || nAsicType == ATIASIC_ID_TONGA_P || nAsicType == ATIASIC_ID_FIJI_P || nAsicType == ATIASIC_ID_ELLESMERE || nAsicType == ATIASIC_ID_BAFFIN || nAsicType == ATIASIC_ID_LEXA || nAsicType == ATIASIC_ID_VEGAM) { GPA_LogMessage("Recognized a GFX8 card."); rASICInfo.eAsicType = ASIC_Gfx8; } else if (nAsicType == ATIASIC_ID_CARRIZO || nAsicType == ATIASIC_ID_STONEY) { GPA_LogMessage("Recognized an APU with GFX8 graphics."); rASICInfo.eAsicType = ASIC_Gfx8; } else if (nAsicType == ATIASIC_ID_GFX900 || nAsicType == ATIASIC_ID_PLACEHOLDER1 || nAsicType == ATIASIC_ID_GFX906) { GPA_LogMessage("Recognized a GFX9 card."); rASICInfo.eAsicType = ASIC_Gfx9; } else if (nAsicType == ATIASIC_ID_GFX902 || nAsicType == ATIASIC_ID_PLACEHOLDER) { GPA_LogMessage("Recognized an APU with GFX9 graphics."); rASICInfo.eAsicType = ASIC_Gfx9; } else { std::stringstream errorMessage; errorMessage << "Unrecognized asic type: " << nAsicType << "."; GPA_LogError(errorMessage.str().c_str()); assert(0); // Unknown ASIC Type, need to update enums list from UGL driver rASICInfo.eAsicType = ASIC_UNKNOWN; return false; } // Now, fill in the rest of the ASIC structure switch (rASICInfo.eAsicType) { case ASIC_Gfx6: case ASIC_Gfx7: case ASIC_Gfx8: case ASIC_Gfx9: if (!GetCounterValue(nASICGroupId, "GPIN_001", rASICInfo.nNumSIMD)) { GPA_LogError("Unable to query GPIN_001."); return false; } if (!GetCounterValue(nASICGroupId, "GPIN_002", rASICInfo.nNumQuadPipe)) { GPA_LogError("Unable to query GPIN_002."); return false; } if (!GetCounterValue(nASICGroupId, "GPIN_003", rASICInfo.nNumRB)) { GPA_LogError("Unable to query GPIN_003."); return false; } if (!GetCounterValue(nASICGroupId, "GPIN_004", rASICInfo.nNumSPI)) { GPA_LogError("Unable to query GPIN_004."); return false; } break; default: break; } return true; }
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); } } } } } }
void Canvas::RecalculateOrder(){ // To calculate a correct ordering determining how the modules SC synths // should be executed, we do a simple topological sort on the graph of // connections. It will be calculated whenever a new connection is added. // Note that neither of: // 1) creating a new module // 2) removing any module // 3) removing any connection // may change the topological order, so there is no need to recalculate it // in such cases. // We will need to remember the current (in the sense of the steps of the // toposort algorithm) indegree of each verticle (module). We will use a map // for this. It may look as a waste of efficiency, because this information // might be stored withing a module, but please note this costs us only // O(V+E), since map operations are O(1). std::map<std::shared_ptr<Module>, int> indegrees; // Once we fill the map with initial data for all modules, we will always // assume that all .find()s return a valid iterator, i.e. each module always // has an entry in the map. for(const std::shared_ptr<Module>& m : modules) if(m->templ->has_sc_code) indegrees[m] = 0; // Calculate initial indegrees. for(auto &it : audio_connections) // For each connection for(const IOID& i : it.second) // For each ending indegrees[i.module]++; // Increase the indeg for that module std::stack<std::shared_ptr<Module>> frontier; // Initialize the frontier for(auto &it : indegrees) // Look at all modules... if(it.second == 0) // ... that have 0 indeg, ... frontier.push(it.first); // ... add them. std::list<std::shared_ptr<Module>> ordering; while(!frontier.empty()){ // Get a new module from frontier. std::shared_ptr<Module> current = frontier.top(); frontier.pop(); // Add the current module to the resulting ordering. ordering.push_back(current); std::list<std::shared_ptr<Module>> next_list = GetConnectedModules(current); // For each module that is directly connected after the current one: for(const std::shared_ptr<Module>& m : next_list) if( --indegrees[m] == 0) // Decrease the indeg, also it it's zero, then add the module to frontier. frontier.push(m); } if(ordering.size() != indegrees.size()){ // Failure. We did not traverse all modules. This can only happen // if the connection graph has a cycle. // The ordering is inconclusive. throw Exceptions::ConnectionLoop(""); } /* // For debugging purposes, demonstrate when the computed odrer is. std::cout << "New synth ordering:" << std::endl; for(const std::shared_ptr<Module> &m : ordering) std::cout << " \"" << m->templ->name << "\"" << std::endl; */ // Send the ordering to SC. lo::Message msg; for(const std::shared_ptr<Module> &m : ordering){ auto subpatch = std::dynamic_pointer_cast<Builtin::Subpatch>(m); if(subpatch){ // Special cas for builtin subpatch module. Ordering full node groups (subtrees) msg.add_int32(subpatch->GetGroupID()); msg.add_int32(m->sc_id); }else{ msg.add_int32(m->sc_id); } } SCLang::SendOSCCustom("/algaudioSC/ordering", msg); }