std::string CSelectedUnits::GetTooltip(void)
{
	std::string s;
	if(selectedGroup!=-1 && grouphandler->groups[selectedGroup]->ai){
		s="Group selected";
	} else if(!selectedUnits.empty()){
		// show the player name instead of unit name if it has FBI tag showPlayerName
		if((*selectedUnits.begin())->unitDef->showPlayerName)
		{
			s=gs->players[gs->Team((*selectedUnits.begin())->team)->leader]->playerName.c_str();
		} else {
			s=(*selectedUnits.begin())->tooltip;
		}
	}
	if(selectedUnits.empty()){
		return s;
	}
	char tmp[500];
	float maxHealth=0,curHealth=0,cost=0,exp=0,range=0,metalMake=0,metalUse=0,energyMake=0,energyUse=0,maxfuel=0,curfuel=0,numfuel=0;
	for(set<CUnit*>::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
		maxHealth+=(*ui)->maxHealth;
		curHealth+=(*ui)->health;
		exp+=(*ui)->experience;
		cost+=(*ui)->metalCost+(*ui)->energyCost/60;
		range+=(*ui)->maxRange;
		metalMake+=(*ui)->metalMake;
		metalUse+=(*ui)->metalUse;
		energyMake+=(*ui)->energyMake;
		energyUse+=(*ui)->energyUse;
		maxfuel+=(*ui)->unitDef->maxFuel;
		curfuel+=(*ui)->currentFuel;
		if((*ui)->unitDef->maxFuel > 0)
			numfuel++;
	}
	float num=selectedUnits.size();
	sprintf(tmp,"\nHealth %.0f/%.0f",curHealth,maxHealth);
	s+=tmp;

	if(maxfuel>0){
		sprintf(tmp," Fuel %.0f/%.0f",curfuel/numfuel,maxfuel/numfuel);
		s+=tmp;
	}

	sprintf(tmp,"\nExperience %.2f Cost %.0f Range %.0f \n\xff\xd3\xdb\xffMetal: \xff\x50\xff\x50%.1f\xff\x90\x90\x90/\xff\xff\x50\x01-%.1f\xff\xd3\xdb\xff Energy: \xff\x50\xff\x50%.1f\xff\x90\x90\x90/\xff\xff\x50\x01-%.1f",
	        exp/num,cost,range/num, metalMake, metalUse, energyMake, energyUse);
	s += tmp;
	
  if (gs->cheatEnabled && (selectedUnits.size() == 1)) {
  	CUnit* unit = *selectedUnits.begin();
    SNPRINTF(tmp, sizeof(tmp), "\xff\xc0\xc0\xff  [TechLevel %i]",
             unit->unitDef->techLevel);
    s += tmp;
	}

	return s;
}
void CSelectedUnits::SetCommandPage(int page)
{
	if(selectedGroup!=-1 && grouphandler->groups[selectedGroup]->ai){
		grouphandler->groups[selectedGroup]->lastCommandPage=page;
	}
	if(!selectedUnits.empty())
		(*selectedUnits.begin())->commandAI->lastSelectedCommandPage=page;
}
Example #3
0
// CALLINFO:
// CTooltipConsole::Draw --> CMouseHandler::GetCurrentTooltip
// LuaUnsyncedRead::GetCurrentTooltip --> CMouseHandler::GetCurrentTooltip
// CMouseHandler::GetCurrentTooltip --> CMiniMap::GetToolTip --> GetTooltip
// CMouseHandler::GetCurrentTooltip --> GetTooltip
std::string CSelectedUnits::GetTooltip(void)
{
	GML_RECMUTEX_LOCK(sel); // GetTooltip - called from TooltipConsole::Draw --> MouseHandler::GetCurrentTooltip --> GetTooltip
	GML_RECMUTEX_LOCK(group); // GetTooltip

	std::string s = "";
	if (!selectedUnits.empty()) {
		// show the player name instead of unit name if it has FBI tag showPlayerName
		if ((*selectedUnits.begin())->unitDef->showPlayerName) {
			if (teamHandler->Team((*selectedUnits.begin())->team)->leader >= 0)
				s = playerHandler->Player(teamHandler->Team((*selectedUnits.begin())->team)->leader)->name.c_str();
			else
				s = "Uncontrolled";
		} else {
			s = (*selectedUnits.begin())->tooltip;
		}
	}

	if (selectedUnits.empty()) {
		return s;
	}

	const string custom = eventHandler.WorldTooltip(NULL, NULL, NULL);
	if (!custom.empty()) {
		return custom;
	}

	char tmp[500];
	int numFuel = 0;
	float maxHealth = 0.0f, curHealth = 0.0f;
	float maxFuel = 0.0f, curFuel = 0.0f;
	float exp = 0.0f, cost = 0.0f, range = 0.0f;
	float metalMake = 0.0f, metalUse = 0.0f, energyMake = 0.0f, energyUse = 0.0f;

	CUnitSet::iterator ui;
	for (ui = selectedUnits.begin(); ui != selectedUnits.end(); ++ui) {
		const CUnit* unit = *ui;
		maxHealth  += unit->maxHealth;
		curHealth  += unit->health;
		exp        += unit->experience;
		cost       += unit->metalCost + (unit->energyCost / 60.0f);
		range      += unit->maxRange;
		metalMake  += unit->metalMake;
		metalUse   += unit->metalUse;
		energyMake += unit->energyMake;
		energyUse  += unit->energyUse;
		maxFuel    += unit->unitDef->maxFuel;
		curFuel    += unit->currentFuel;
		if (unit->unitDef->maxFuel > 0) {
			numFuel++;
		}
	}
	if ((numFuel > 0) && (maxFuel > 0.0f)) {
		curFuel = curFuel / numFuel;
		maxFuel = maxFuel / numFuel;
	}
	const float num = selectedUnits.size();

	s += CTooltipConsole::MakeUnitStatsString(
	       curHealth, maxHealth,
	       curFuel,   maxFuel,
	       (exp / num), cost, (range / num),
	       metalMake,  metalUse,
	       energyMake, energyUse);

  if (gs->cheatEnabled && (selectedUnits.size() == 1)) {
  	CUnit* unit = *selectedUnits.begin();
    SNPRINTF(tmp, sizeof(tmp), "\xff\xc0\xc0\xff  [TechLevel %i]",
             unit->unitDef->techLevel);
    s += tmp;
	}

	return s;
}
Example #4
0
void CSelectedUnits::Draw()
{
	glDisable(GL_TEXTURE_2D);
	glDepthMask(false);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND); // for line smoothing
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glLineWidth(cmdColors.UnitBoxLineWidth());

	GML_RECMUTEX_LOCK(sel); // Draw
	GML_RECMUTEX_LOCK(group); // Draw

	if (cmdColors.unitBox[3] > 0.0f) {
		glColor4fv(cmdColors.unitBox);

		const CUnitSet* unitSet;
		if (selectedGroup != -1) {
			unitSet = &grouphandlers[gu->myTeam]->groups[selectedGroup]->units;
		} else {
			unitSet = &selectedUnits;
		}

		glBegin(GL_QUADS);
		CUnitSet::const_iterator ui;
		for (ui = unitSet->begin(); ui != unitSet->end(); ++ui) {
			const CUnit* unit = *ui;
			if (unit->isIcon) {
				continue;
			}

			glVertexf3(unit->drawPos + float3( unit->xsize * 4, 0,  unit->zsize * 4));
			glVertexf3(unit->drawPos + float3(-unit->xsize * 4, 0,  unit->zsize * 4));
			glVertexf3(unit->drawPos + float3(-unit->xsize * 4, 0, -unit->zsize * 4));
			glVertexf3(unit->drawPos + float3( unit->xsize * 4, 0, -unit->zsize * 4));
		}
		glEnd();
	}

	// highlight queued build sites if we are about to build something
	// (or old-style, whenever the shift key is being held down)
	if (cmdColors.buildBox[3] > 0.0f) {
		if (!selectedUnits.empty() &&
				((cmdColors.BuildBoxesOnShift() && keys[SDLK_LSHIFT]) ||
				 ((guihandler->inCommand >= 0) &&
					(guihandler->inCommand < int(guihandler->commands.size())) &&
					(guihandler->commands[guihandler->inCommand].id < 0)))) {

			GML_STDMUTEX_LOCK(cai); // Draw

			bool myColor = true;
			glColor4fv(cmdColors.buildBox);
			std::list<CBuilderCAI*>::const_iterator bi;
			for (bi = uh->builderCAIs.begin(); bi != uh->builderCAIs.end(); ++bi) {
				CBuilderCAI* builder = *bi;
				if (builder->owner->team == gu->myTeam) {
					if (!myColor) {
						glColor4fv(cmdColors.buildBox);
						myColor = true;
					}
					builder->DrawQuedBuildingSquares();
				}
				else if (teamHandler->AlliedTeams(builder->owner->team, gu->myTeam)) {
					if (myColor) {
						glColor4fv(cmdColors.allyBuildBox);
						myColor = false;
					}
					builder->DrawQuedBuildingSquares();
				}
			}
		}
	}

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glDepthMask(true);
	glEnable(GL_TEXTURE_2D);
}
Example #5
0
void CSelectedUnits::GiveCommand(Command c, bool fromUser)
{
	GML_RECMUTEX_LOCK(sel); // GiveCommand
	GML_RECMUTEX_LOCK(group); // GiveCommand

//	logOutput.Print("Command given %i",c.id);
	if ((gu->spectating && !gs->godMode) || selectedUnits.empty()) {
		return;
	}

	if (fromUser) {		//add some statistics
		playerHandler->Player(gu->myPlayerNum)->currentStats.numCommands++;
		if (selectedGroup!=-1) {
			playerHandler->Player(gu->myPlayerNum)->currentStats.unitCommands+=grouphandlers[gu->myTeam]->groups[selectedGroup]->units.size();
		} else {
			playerHandler->Player(gu->myPlayerNum)->currentStats.unitCommands+=selectedUnits.size();
		}
	}

	if (c.id == CMD_GROUPCLEAR) {
		for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
			if((*ui)->group){
				(*ui)->SetGroup(0);
				possibleCommandsChanged=true;
			}
		}
		return;
	}
	else if (c.id == CMD_GROUPSELECT) {
		SelectGroup((*selectedUnits.begin())->group->id);
		return;
	}
	else if (c.id == CMD_GROUPADD) {
		CGroup* group=0;
		for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
			if((*ui)->group){
				group=(*ui)->group;
				possibleCommandsChanged=true;
				break;
			}
		}
		if(group){
			for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
				if(!(*ui)->group)
					(*ui)->SetGroup(group);
			}
			SelectGroup(group->id);
		}
		return;
	}
	else if (c.id == CMD_AISELECT) {
		if (gs->noHelperAIs) {
			logOutput.Print("LuaUI control is disabled");
			return;
		}
		if(c.params[0]!=0){
			CGroup* group=grouphandlers[gu->myTeam]->CreateNewGroup();

			for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
				(*ui)->SetGroup(group);
			}
			SelectGroup(group->id);
		}
		return;
	}
	else if (c.id == CMD_TIMEWAIT) {
		waitCommandsAI.AddTimeWait(c);
		return;
	}
	else if (c.id == CMD_DEATHWAIT) {
		if (teamHandler->ActiveAllyTeams() <= 2) {
			waitCommandsAI.AddDeathWait(c);
		} else {
			logOutput.Print("DeathWait can only be used when there are 2 Ally Teams");
		}
		return;
	}
	else if (c.id == CMD_SQUADWAIT) {
		waitCommandsAI.AddSquadWait(c);
		return;
	}
	else if (c.id == CMD_GATHERWAIT) {
		waitCommandsAI.AddGatherWait(c);
		return;
	}

	SendCommand(c);

	if (!selectedUnits.empty()) {
		CUnitSet::iterator ui = selectedUnits.begin();

		int soundIdx = (*ui)->unitDef->sounds.ok.getRandomIdx();
		if (soundIdx >= 0) {
			Channels::UnitReply.PlaySample(
				(*ui)->unitDef->sounds.ok.getID(soundIdx), (*ui),
				(*ui)->unitDef->sounds.ok.getVolume(soundIdx));
		}
	}
}
void CSelectedUnits::GiveCommand(Command c,bool fromUser)
{
//	info->AddLine("Command given %i",c.id);
	if(gu->spectating || selectedUnits.empty())
		return;

	if(fromUser){		//add some statistics
		gs->players[gu->myPlayerNum]->currentStats->numCommands++;
		if(selectedGroup!=-1){
			gs->players[gu->myPlayerNum]->currentStats->unitCommands+=grouphandler->groups[selectedGroup]->units.size();
		} else {
			gs->players[gu->myPlayerNum]->currentStats->unitCommands+=selectedUnits.size();
		}
	}

	if(c.id==CMD_GROUPCLEAR){
		for(set<CUnit*>::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
			if((*ui)->group)
				(*ui)->SetGroup(0);
		}
		return;
	}

	if(selectedGroup!=-1 && (grouphandler->groups[selectedGroup]->ai || c.id==CMD_AISELECT)){
		grouphandler->groups[selectedGroup]->GiveCommand(c);
		return;
	}

	if(c.id==CMD_GROUPSELECT){
		SelectGroup((*selectedUnits.begin())->group->id);
		return;
	}

	if(c.id==CMD_GROUPADD){
		CGroup* group=0;
		for(set<CUnit*>::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
			if((*ui)->group){
				group=(*ui)->group;
				break;
			}
		}
		if(group){
			for(set<CUnit*>::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
				if(!(*ui)->group)
					(*ui)->SetGroup(group);
			}	
			SelectGroup(group->id);
		}
		return;
	}

	if(c.id==CMD_AISELECT){
		if(c.params[0]!=0){
			map<string,string>::iterator aai;
			int a=0;
			for(aai=grouphandler->availableAI.begin();aai!=grouphandler->availableAI.end() && a<c.params[0]-1;++aai){
				a++;
			}
			CGroup* group=grouphandler->CreateNewGroup(aai->first);

			for(set<CUnit*>::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
				(*ui)->SetGroup(group);
			}
			SelectGroup(group->id);
		}
		return;
	}
//	selectedUnitsAI.GiveCommand(c);

	SendCommand(c);

	if(!selectedUnits.empty()){
		set<CUnit*>::iterator ui = selectedUnits.begin();
		if((*ui)->unitDef->sounds.ok.id)
			sound->PlayUnitReply((*ui)->unitDef->sounds.ok.id, (*ui), (*ui)->unitDef->sounds.ok.volume, true);
	}
}
Example #7
0
// CALLINFO:
// CTooltipConsole::Draw --> CMouseHandler::GetCurrentTooltip
// LuaUnsyncedRead::GetCurrentTooltip --> CMouseHandler::GetCurrentTooltip
// CMouseHandler::GetCurrentTooltip --> CMiniMap::GetToolTip --> GetTooltip
// CMouseHandler::GetCurrentTooltip --> GetTooltip
std::string CSelectedUnits::GetTooltip()
{
	std::string s = "";
	{
		GML_RECMUTEX_LOCK(sel); // GetTooltip - called from TooltipConsole::Draw --> MouseHandler::GetCurrentTooltip --> GetTooltip

		if (!selectedUnits.empty()) {
			const CUnit* unit = (*selectedUnits.begin());
			const CTeam* team = NULL;

			// show the player name instead of unit name if it has FBI tag showPlayerName
			if (unit->unitDef->showPlayerName) {
				team = teamHandler->Team(unit->team);
				s = team->GetControllerName();
			} else {
				s = (*selectedUnits.begin())->tooltip;
			}

		}

		if (selectedUnits.empty()) {
			return s;
		}
	}

	const string custom = eventHandler.WorldTooltip(NULL, NULL, NULL);
	if (!custom.empty()) {
		return custom;
	}

	{
		GML_RECMUTEX_LOCK(sel); // GetTooltip

		char tmp[500];
		int numFuel = 0;
		float maxHealth = 0.0f, curHealth = 0.0f;
		float maxFuel = 0.0f, curFuel = 0.0f;
		float exp = 0.0f, cost = 0.0f, range = 0.0f;
		float metalMake = 0.0f, metalUse = 0.0f, energyMake = 0.0f, energyUse = 0.0f;

#define NO_TEAM -32
#define MULTI_TEAM -64
		int ctrlTeam = NO_TEAM;

		CUnitSet::const_iterator ui;
		for (ui = selectedUnits.begin(); ui != selectedUnits.end(); ++ui) {
			const CUnit* unit = *ui;
			maxHealth  += unit->maxHealth;
			curHealth  += unit->health;
			exp        += unit->experience;
			cost       += unit->metalCost + (unit->energyCost / 60.0f);
			range      += unit->maxRange;
			metalMake  += unit->metalMake;
			metalUse   += unit->metalUse;
			energyMake += unit->energyMake;
			energyUse  += unit->energyUse;
			maxFuel    += unit->unitDef->maxFuel;
			curFuel    += unit->currentFuel;
			if (unit->unitDef->maxFuel > 0) {
				numFuel++;
			}
			if (ctrlTeam == NO_TEAM) {
				ctrlTeam = unit->team;
			} else if (ctrlTeam != unit->team) {
				ctrlTeam = MULTI_TEAM;
			}
		}
		if ((numFuel > 0) && (maxFuel > 0.0f)) {
			curFuel = curFuel / numFuel;
			maxFuel = maxFuel / numFuel;
		}
		const float num = selectedUnits.size();

		s += CTooltipConsole::MakeUnitStatsString(
			curHealth, maxHealth,
			curFuel,   maxFuel,
			(exp / num), cost, (range / num),
			metalMake,  metalUse,
			energyMake, energyUse);

		if (gs->cheatEnabled && (num == 1)) {
			const CUnit* unit = *selectedUnits.begin();
			SNPRINTF(tmp, sizeof(tmp), "\xff\xc0\xc0\xff  [TechLevel %i]",
				unit->unitDef->techLevel);
			s += tmp;
		}

		std::string ctrlName = "";
		if (ctrlTeam == MULTI_TEAM) {
			ctrlName = "(Multiple teams)";
		} else if (ctrlTeam != NO_TEAM) {
			ctrlName = teamHandler->Team(ctrlTeam)->GetControllerName();
		}
		s += "\n\xff\xff\xff\xff" + ctrlName;

		return s;
	}
}
Example #8
0
void CSelectedUnits::Draw()
{
	glDisable(GL_TEXTURE_2D);
	glDepthMask(false);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_BLEND); // for line smoothing
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	glLineWidth(cmdColors.UnitBoxLineWidth());

	GML_RECMUTEX_LOCK(grpsel); // Draw

	if (cmdColors.unitBox[3] > 0.05f) {
		const CUnitSet* unitSet;
		if (selectedGroup != -1) {
			unitSet = &grouphandlers[gu->myTeam]->groups[selectedGroup]->units;
		} else {
			unitSet = &selectedUnits;
		}

		CVertexArray* va = GetVertexArray();
		va->Initialize();
		va->EnlargeArrays(unitSet->size() * 8, 0, VA_SIZE_C);

		for (CUnitSet::const_iterator ui = unitSet->begin(); ui != unitSet->end(); ++ui) {
			const CUnit* unit = *ui;
			if (unit->isIcon) {
				continue;
			}

			const int
				uhxsize = (unit->xsize * SQUARE_SIZE) >> 1,
				uhzsize = (unit->zsize * SQUARE_SIZE) >> 1,
				mhxsize = (unit->mobility == NULL)? uhxsize: ((unit->mobility->xsize * SQUARE_SIZE) >> 1),
				mhzsize = (unit->mobility == NULL)? uhzsize: ((unit->mobility->zsize * SQUARE_SIZE) >> 1);
			const float3 verts[8] = {
				// UnitDef footprint corners
				float3(unit->drawPos.x + uhxsize, unit->drawPos.y, unit->drawPos.z + uhzsize),
				float3(unit->drawPos.x - uhxsize, unit->drawPos.y, unit->drawPos.z + uhzsize),
				float3(unit->drawPos.x - uhxsize, unit->drawPos.y, unit->drawPos.z - uhzsize),
				float3(unit->drawPos.x + uhxsize, unit->drawPos.y, unit->drawPos.z - uhzsize),
				// MoveDef footprint corners
				float3(unit->drawPos.x + mhxsize, unit->drawPos.y, unit->drawPos.z + mhzsize),
				float3(unit->drawPos.x - mhxsize, unit->drawPos.y, unit->drawPos.z + mhzsize),
				float3(unit->drawPos.x - mhxsize, unit->drawPos.y, unit->drawPos.z - mhzsize),
				float3(unit->drawPos.x + mhxsize, unit->drawPos.y, unit->drawPos.z - mhzsize),
			};

			const unsigned char colors[2][4] = {
				{(0.0f + cmdColors.unitBox[0]) * 255, (0.0f + cmdColors.unitBox[1]) * 255, (0.0f + cmdColors.unitBox[2] * 255), cmdColors.unitBox[3] * 255},
				{(1.0f - cmdColors.unitBox[0]) * 255, (1.0f - cmdColors.unitBox[1]) * 255, (1.0f - cmdColors.unitBox[2] * 255), cmdColors.unitBox[3] * 255},
			};

			va->AddVertexQC(verts[0], colors[0]);
			va->AddVertexQC(verts[1], colors[0]);
			va->AddVertexQC(verts[2], colors[0]);
			va->AddVertexQC(verts[3], colors[0]);

			if (globalRendering->drawdebug && (mhxsize != uhxsize || mhzsize != uhzsize)) {
				va->AddVertexQC(verts[4], colors[1]);
				va->AddVertexQC(verts[5], colors[1]);
				va->AddVertexQC(verts[6], colors[1]);
				va->AddVertexQC(verts[7], colors[1]);
			}
		}

		va->DrawArrayC(GL_QUADS);
	}

	// highlight queued build sites if we are about to build something
	// (or old-style, whenever the shift key is being held down)
	if (cmdColors.buildBox[3] > 0.0f) {
		if (!selectedUnits.empty() &&
				((cmdColors.BuildBoxesOnShift() && keyInput->IsKeyPressed(SDLK_LSHIFT)) ||
				 ((guihandler->inCommand >= 0) &&
					(guihandler->inCommand < int(guihandler->commands.size())) &&
					(guihandler->commands[guihandler->inCommand].id < 0)))) {

			GML_STDMUTEX_LOCK(cai); // Draw

			bool myColor = true;
			glColor4fv(cmdColors.buildBox);
			std::list<CBuilderCAI*>::const_iterator bi;
			for (bi = uh->builderCAIs.begin(); bi != uh->builderCAIs.end(); ++bi) {
				CBuilderCAI* builder = *bi;
				if (builder->owner->team == gu->myTeam) {
					if (!myColor) {
						glColor4fv(cmdColors.buildBox);
						myColor = true;
					}
					commandDrawer->DrawQuedBuildingSquares(builder);
				}
				else if (teamHandler->AlliedTeams(builder->owner->team, gu->myTeam)) {
					if (myColor) {
						glColor4fv(cmdColors.allyBuildBox);
						myColor = false;
					}
					commandDrawer->DrawQuedBuildingSquares(builder);
				}
			}
		}
	}

	glLineWidth(1.0f);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glDepthMask(true);
	glEnable(GL_TEXTURE_2D);
}
Example #9
0
void CSelectedUnits::GiveCommand(Command c, bool fromUser)
{
	GML_RECMUTEX_LOCK(grpsel); // GiveCommand

//	LOG_L(L_DEBUG, "Command given %i", c.id);
	if ((gu->spectating && !gs->godMode) || selectedUnits.empty()) {
		return;
	}

	const int& cmd_id = c.GetID();

	if (fromUser) { // add some statistics
		playerHandler->Player(gu->myPlayerNum)->currentStats.numCommands++;
		if (selectedGroup != -1) {
			playerHandler->Player(gu->myPlayerNum)->currentStats.unitCommands += grouphandlers[gu->myTeam]->groups[selectedGroup]->units.size();
		} else {
			playerHandler->Player(gu->myPlayerNum)->currentStats.unitCommands += selectedUnits.size();
		}
	}

	if (cmd_id == CMD_GROUPCLEAR) {
		for (CUnitSet::iterator ui = selectedUnits.begin(); ui != selectedUnits.end(); ++ui) {
			if ((*ui)->group) {
				(*ui)->SetGroup(0);
				possibleCommandsChanged = true;
			}
		}
		return;
	}
	else if (cmd_id == CMD_GROUPSELECT) {
		SelectGroup((*selectedUnits.begin())->group->id);
		return;
	}
	else if (cmd_id == CMD_GROUPADD) {
		CGroup* group = NULL;
		for (CUnitSet::iterator ui = selectedUnits.begin(); ui != selectedUnits.end(); ++ui) {
			if ((*ui)->group) {
				group = (*ui)->group;
				possibleCommandsChanged = true;
				break;
			}
		}
		if (group) {
			for (CUnitSet::iterator ui = selectedUnits.begin(); ui != selectedUnits.end(); ++ui) {
				if (!(*ui)->group) {
					(*ui)->SetGroup(group);
				}
			}
			SelectGroup(group->id);
		}
		return;
	}
	else if (cmd_id == CMD_TIMEWAIT) {
		waitCommandsAI.AddTimeWait(c);
		return;
	}
	else if (cmd_id == CMD_DEATHWAIT) {
		waitCommandsAI.AddDeathWait(c);
		return;
	}
	else if (cmd_id == CMD_SQUADWAIT) {
		waitCommandsAI.AddSquadWait(c);
		return;
	}
	else if (cmd_id == CMD_GATHERWAIT) {
		waitCommandsAI.AddGatherWait(c);
		return;
	}

	SendCommand(c);

	#if (PLAY_SOUNDS == 1)
	if (!selectedUnits.empty()) {
		CUnitSet::const_iterator ui = selectedUnits.begin();

		const int soundIdx = (*ui)->unitDef->sounds.ok.getRandomIdx();
		if (soundIdx >= 0) {
			Channels::UnitReply.PlaySample(
				(*ui)->unitDef->sounds.ok.getID(soundIdx), (*ui),
				(*ui)->unitDef->sounds.ok.getVolume(soundIdx));
		}
	}
	#endif
}
void CSelectedUnits::GiveCommand(Command c, bool fromUser)
{
//	logOutput.Print("Command given %i",c.id);
	if ((gu->spectating && !gs->godMode) || selectedUnits.empty()) {
		return;
	}

	if (fromUser) {		//add some statistics
		gs->players[gu->myPlayerNum]->currentStats->numCommands++;
		if (selectedGroup!=-1) {
			gs->players[gu->myPlayerNum]->currentStats->unitCommands+=grouphandlers[gu->myTeam]->groups[selectedGroup]->units.size();
		} else {
			gs->players[gu->myPlayerNum]->currentStats->unitCommands+=selectedUnits.size();
		}
	}

	if (c.id == CMD_GROUPCLEAR) {
		for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
			if((*ui)->group){
				(*ui)->SetGroup(0);
				possibleCommandsChanged=true;
			}
		}
		return;
	}
	else if (c.id == CMD_GROUPSELECT) {
		SelectGroup((*selectedUnits.begin())->group->id);
		return;
	}
	else if (c.id == CMD_GROUPADD) {
		CGroup* group=0;
		for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
			if((*ui)->group){
				group=(*ui)->group;
				possibleCommandsChanged=true;
				break;
			}
		}
		if(group){
			for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
				if(!(*ui)->group)
					(*ui)->SetGroup(group);
			}
			SelectGroup(group->id);
		}
		return;
	}
	else if (c.id == CMD_AISELECT) {
		if (gs->noHelperAIs) {
			logOutput.Print("GroupAI and LuaUI control is disabled");
			return;
		}
		if(c.params[0]!=0){
			map<AIKey,string>::iterator aai;
			int a=0;
			for(aai=grouphandlers[gu->myTeam]->lastSuitedAis.begin();aai!=grouphandlers[gu->myTeam]->lastSuitedAis.end() && a<c.params[0]-1;++aai){
				a++;
			}
			CGroup* group=grouphandlers[gu->myTeam]->CreateNewGroup(aai->first);

			for(CUnitSet::iterator ui=selectedUnits.begin();ui!=selectedUnits.end();++ui){
				(*ui)->SetGroup(group);
			}
			SelectGroup(group->id);
		}
		return;
	}
	else if (c.id == CMD_TIMEWAIT) {
		waitCommandsAI.AddTimeWait(c);
		return;
	}
	else if (c.id == CMD_DEATHWAIT) {
		if (gs->activeAllyTeams <= 2) {
			waitCommandsAI.AddDeathWait(c);
		} else {
			logOutput.Print("DeathWait can only be used when there are 2 Ally Teams");
		}
		return;
	}
	else if (c.id == CMD_SQUADWAIT) {
		waitCommandsAI.AddSquadWait(c);
		return;
	}
	else if (c.id == CMD_GATHERWAIT) {
		waitCommandsAI.AddGatherWait(c);
		return;
	}

//	FIXME:  selectedUnitsAI.GiveCommand(c);

	if ((selectedGroup != -1) && grouphandlers[gu->myTeam]->groups[selectedGroup]->ai) {
		grouphandlers[gu->myTeam]->groups[selectedGroup]->GiveCommand(c);
		return;
	}

	SendCommand(c);

	if (!selectedUnits.empty()) {
		CUnitSet::iterator ui = selectedUnits.begin();

		int soundIdx = (*ui)->unitDef->sounds.ok.getRandomIdx();
		if (soundIdx >= 0) {
			sound->PlayUnitReply(
				(*ui)->unitDef->sounds.ok.getID(soundIdx), (*ui),
				(*ui)->unitDef->sounds.ok.getVolume(soundIdx), true);
		}
	}
}