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());
}
Exemple #10
0
//=========================================================================================================
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(&amp);
					}
				}
			}
			//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(&amp);
			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(&amp);
					//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);
					}
				}
			}
		}
	}
}
Exemple #13
0
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);

}