コード例 #1
0
ファイル: WaitCommandsAI.cpp プロジェクト: FriedRice/spring
void CWaitCommandsAI::SquadWait::RemoveUnit(CUnit* unit)
{
	if (buildUnits.erase(unit))
		DeleteDeathDependence(unit, DEPENDENCE_WAITCMD);
	if (waitUnits.erase(unit))
		DeleteDeathDependence(unit, DEPENDENCE_WAITCMD);
}
コード例 #2
0
void CWaitCommandsAI::SquadWait::RemoveUnit(CUnit* unit)
{
	CUnitSet::iterator bit = buildUnits.find(unit);
	if (bit != buildUnits.end()) {
		DeleteDeathDependence(*bit);
		buildUnits.erase(bit);
	}
	CUnitSet::iterator wit = waitUnits.find(unit);
	if (wit != waitUnits.end()) {
		DeleteDeathDependence(*wit);
		waitUnits.erase(wit);
	}
}
コード例 #3
0
bool CWeapon::AttackGround(float3 pos, bool userTarget)
{
	if (!userTarget && weaponDef->noAutoTarget) {
		return false;
	}
	if (weaponDef->interceptor || !weaponDef->canAttackGround ||
	    (weaponDef->onlyTargetCategory != 0xffffffff)) {
		return false;
	}

	if (!weaponDef->waterweapon && (pos.y < 1.0f)) {
		pos.y = 1.0f;
	}
	weaponMuzzlePos=owner->pos+owner->frontdir*relWeaponMuzzlePos.z+owner->updir*relWeaponMuzzlePos.y+owner->rightdir*relWeaponMuzzlePos.x;
	if(weaponMuzzlePos.y<ground->GetHeight2(weaponMuzzlePos.x,weaponMuzzlePos.z))
		weaponMuzzlePos=owner->pos+UpVector*10;		//hope that we are underground because we are a popup weapon and will come above ground later

	if(!TryTarget(pos,userTarget,0))
		return false;
	if(targetUnit){
		DeleteDeathDependence(targetUnit);
		targetUnit=0;
	}
	haveUserTarget=userTarget;
	targetType=Target_Pos;
	targetPos=pos;
	return true;
}
コード例 #4
0
ファイル: CommandAI.cpp プロジェクト: Gepard/spring
CCommandAI::~CCommandAI()
{
	if (orderTarget) {
		DeleteDeathDependence(orderTarget);
		orderTarget = 0;
	}
}
コード例 #5
0
ファイル: AirMoveType.cpp プロジェクト: Dmytry/spring
void CAirMoveType::CheckForCollision(void)
{
	if (!collide) return;

	SyncedFloat3& pos = owner->midPos;
	SyncedFloat3& forward = owner->frontdir;
	float3 midTestPos = pos + forward * 121;

	std::vector<CUnit*> others = qf->GetUnitsExact(midTestPos, 115);

	float dist = 200;
	if (lastColWarning) {
		DeleteDeathDependence(lastColWarning);
		lastColWarning = 0;
		lastColWarningType = 0;
	}

	for (std::vector<CUnit*>::iterator ui = others.begin(); ui != others.end(); ++ui) {
		if (*ui == owner || !(*ui)->unitDef->canfly)
			continue;
		SyncedFloat3& op = (*ui)->midPos;
		float3 dif = op - pos;
		float3 forwardDif = forward * (forward.dot(dif));
		if (forwardDif.SqLength() < dist * dist) {
			float frontLength = forwardDif.Length();
			float3 ortoDif = dif - forwardDif;

			// note that the radii are multiplied by two since we rely on
			// aircraft having half-size hitspheres (see unitloader)
			//
			// FIXME: with the new collision volumes, is this still true?
			//
			// yes: for backward compatibility, aircraft that do not define
			// their own custom volumes get halved hitspheres by default

			float minOrtoDif = ((*ui)->radius + owner->radius) * 2 + frontLength * 0.1f + 10;
			if (ortoDif.SqLength() < minOrtoDif * minOrtoDif) {
				dist = frontLength;
				lastColWarning = (*ui);
			}
		}
	}
	if (lastColWarning) {
		lastColWarningType = 2;
		AddDeathDependence(lastColWarning);
		return;
	}
	for (std::vector<CUnit*>::iterator ui = others.begin(); ui != others.end(); ++ui) {
		if (*ui == owner)
			continue;
		if (((*ui)->midPos - pos).SqLength() < dist * dist) {
			lastColWarning = *ui;
		}
	}
	if (lastColWarning) {
		lastColWarningType = 1;
		AddDeathDependence(lastColWarning);
	}
	return;
}
コード例 #6
0
bool CWeapon::AttackUnit(CUnit *unit,bool userTarget)
{
    if((!userTarget && weaponDef->noAutoTarget))
        return false;
    if(weaponDef->interceptor)
        return false;

    weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x;
    if(weaponPos.y<ground->GetHeight2(weaponPos.x,weaponPos.z))
        weaponPos=owner->pos+10;		//hope that we are underground because we are a popup weapon and will come above ground later

    if(!unit) {
        if(targetType!=Target_Unit)			//make the unit be more likely to keep the current target if user start to move it
            targetType=Target_None;
        haveUserTarget=false;
        return false;
    }
    float3 targetPos(helper->GetUnitErrorPos(unit,owner->allyteam));
    targetPos+=errorVector*(weaponDef->targetMoveError*30*unit->speed.Length()*(1.0-owner->limExperience));
    if(!TryTarget(targetPos,userTarget,unit))
        return false;

    if(targetUnit) {
        DeleteDeathDependence(targetUnit);
        targetUnit=0;
    }
    haveUserTarget=userTarget;
    targetType=Target_Unit;
    targetUnit=unit;
    targetPos=unit->midPos+float3(0,0.3,0)*unit->radius;
    AddDeathDependence(targetUnit);
    return true;
}
コード例 #7
0
void CWaitCommandsAI::GatherWait::Update()
{
	if (waitUnits.size() < 2) {
		delete this;
		return;
	}

	CUnitSet::iterator it = waitUnits.begin();
	while (it != waitUnits.end()) {
		WaitState state = GetWaitState(*it);
		if (state == Active) {
			// do nothing
		}
		else if(state == Queued) {
			return;
		}
		else if (state == Missing) {
			DeleteDeathDependence(*it);
			it = RemoveUnitFromSet(it, waitUnits);
			if (waitUnits.empty()) {
				delete this;
				return;
			}
			continue;
		}
		++it;
	}

	// all units are actively waiting on this command, unblock them and die
	SendWaitCommand(waitUnits);
	delete this;
}
コード例 #8
0
ファイル: Tasks.cpp プロジェクト: achoum/spring
void RepairTask::SetRepairTarget (aiUnit *u)
{
    if (target) DeleteDeathDependence (target);

    target = u;
    if (u) AddDeathDependence (u);
}
コード例 #9
0
bool CWeapon::AttackUnit(CUnit* unit, bool userTarget)
{
	if ((!userTarget && weaponDef->noAutoTarget))
		return false;
	if (weaponDef->interceptor)
		return false;

	weaponPos =
		owner->pos +
		owner->frontdir * relWeaponPos.z +
		owner->updir    * relWeaponPos.y +
		owner->rightdir * relWeaponPos.x;
	weaponMuzzlePos =
		owner->pos +
		owner->frontdir * relWeaponMuzzlePos.z +
		owner->updir    * relWeaponMuzzlePos.y +
		owner->rightdir * relWeaponMuzzlePos.x;

	if (weaponMuzzlePos.y < ground->GetHeightReal(weaponMuzzlePos.x, weaponMuzzlePos.z)) {
		// hope that we are underground because we are a popup weapon and will come above ground later
		weaponMuzzlePos = owner->pos + UpVector * 10;
	}

	if (!unit) {
		if (targetType != Target_Unit) {
			// make the unit be more likely to keep the current target if user starts to move it
			targetType = Target_None;
		}

		haveUserTarget = false;
		return false;
	}

	float3 tempTargetPos =
		helper->GetUnitErrorPos(unit, owner->allyteam) +
		errorVector * (weaponDef->targetMoveError * GAME_SPEED * unit->speed.Length() * (1.0f - owner->limExperience));

	const float appHeight = ground->GetApproximateHeight(tempTargetPos.x, tempTargetPos.z) + 2.0f;

	if (tempTargetPos.y < appHeight)
		tempTargetPos.y = appHeight;

	if (!TryTarget(tempTargetPos, userTarget, unit))
		return false;

	if (targetUnit) {
		DeleteDeathDependence(targetUnit, DEPENDENCE_TARGETUNIT);
		targetUnit = NULL;
	}

	haveUserTarget = userTarget;
	targetType = Target_Unit;
	targetUnit = unit;
	targetPos = tempTargetPos;

	AddDeathDependence(targetUnit, DEPENDENCE_TARGETUNIT);
	avoidTarget = false;
	return true;
}
コード例 #10
0
ファイル: AirCAI.cpp プロジェクト: BrainDamage/spring
void CAirCAI::ExecuteAreaAttack(Command &c)
{
	assert(owner->unitDef->canAttack);
	AAirMoveType* myPlane = (AAirMoveType*) owner->moveType;

	if (targetDied) {
		targetDied = false;
		inCommand = false;
	}

	const float3 pos(c.params[0], c.params[1], c.params[2]);
	const float radius = c.params[3];

	if (inCommand) {
		if (myPlane->aircraftState == AAirMoveType::AIRCRAFT_LANDED)
			inCommand = false;
		if (orderTarget && orderTarget->pos.SqDistance2D(pos) > Square(radius)) {
			inCommand = false;
			DeleteDeathDependence(orderTarget);
			orderTarget = 0;
		}
		if (owner->commandShotCount < 0) {
			if ((c.params.size() == 4) && (commandQue.size() > 1)) {
				owner->AttackUnit(0, true);
				FinishCommand();
			}
			else if (owner->userAttackGround) {
				// reset the attack position after each run
				float3 attackPos = pos + (gs->randVector() * radius);
					attackPos.y = ground->GetHeightAboveWater(attackPos.x, attackPos.z);

				owner->AttackGround(attackPos, false);
				owner->commandShotCount = 0;
			}
		}
	} else {
		owner->commandShotCount = -1;

		if (myPlane->aircraftState != AAirMoveType::AIRCRAFT_LANDED) {
			inCommand = true;

			std::vector<int> enemyUnitIDs;
			helper->GetEnemyUnits(pos, radius, owner->allyteam, enemyUnitIDs);

			if (enemyUnitIDs.empty()) {
				float3 attackPos = pos + gs->randVector() * radius;
				attackPos.y = ground->GetHeightAboveWater(attackPos.x, attackPos.z);
				owner->AttackGround(attackPos, false);
			} else {
				// note: the range of randFloat() is inclusive of 1.0f
				const unsigned int idx(gs->randFloat() * (enemyUnitIDs.size() - 1));

				orderTarget = uh->GetUnitUnsafe( enemyUnitIDs[idx] );
				owner->AttackUnit(orderTarget, false);
				AddDeathDependence(orderTarget);
			}
		}
	}
}
コード例 #11
0
void CWaitCommandsAI::DeathWait::RemoveUnit(CUnit* unit)
{
	CUnitSet::iterator it = waitUnits.find(unit);
	if (it != waitUnits.end()) {
		DeleteDeathDependence(*it);
		waitUnits.erase(it);
	}
}
コード例 #12
0
ファイル: Unit.cpp プロジェクト: genxinzou/svn-spring-archive
void CUnit::FinishedBuilding(void)
{
	beingBuilt = false;
	buildProgress = 1.0f;

	if (soloBuilder) {
		DeleteDeathDependence(soloBuilder);
		soloBuilder = NULL;
	}

	if (!(immobile && (mass == 100000))) {
		mass = unitDef->mass;		//set this now so that the unit is harder to move during build
	}

	ChangeLos(realLosRadius,realAirLosRadius);

	if (unitDef->startCloaked) {
		wantCloak = true;
		isCloaked = true;
	}

	if (unitDef->windGenerator>0) {
		if (wind.curStrength > unitDef->windGenerator) {
			cob->Call(COBFN_SetSpeed, (int)(unitDef->windGenerator * 3000.0f));
		} else {
			cob->Call(COBFN_SetSpeed, (int)(wind.curStrength       * 3000.0f));
		}
		cob->Call(COBFN_SetDirection, (int)GetHeadingFromVector(-wind.curDir.x, -wind.curDir.z));
	}

	if (unitDef->activateWhenBuilt) {
		Activate();
	}

	gs->Team(team)->metalStorage  += unitDef->metalStorage;
	gs->Team(team)->energyStorage += unitDef->energyStorage;

	//Sets the frontdir in sync with heading.
	frontdir = GetVectorFromHeading(heading) + float3(0,frontdir.y,0);

	if (unitDef->isAirBase) {
		airBaseHandler->RegisterAirBase(this);
	}

	luaCallIns.UnitFinished(this);
	globalAI->UnitFinished(this);

	if (unitDef->isFeature) {
		UnBlock();
		CFeature* f =
			featureHandler->CreateWreckage(pos, wreckName, heading, buildFacing,
			                               0, team, false, "");
		if (f) {
			f->blockHeightChanges = true;
		}
		KillUnit(false, true, 0);
	}
}
コード例 #13
0
void CWeapon::HoldFire()
{
    if(targetUnit) {
        DeleteDeathDependence(targetUnit);
        targetUnit=0;
    }
    targetType=Target_None;
    haveUserTarget=false;
}
コード例 #14
0
ファイル: TAAirMoveType.cpp プロジェクト: Dmytry/spring
void CTAAirMoveType::CheckForCollision(void)
{
	if (!collide) return;

	SyncedFloat3& pos = owner->midPos;
	SyncedFloat3 forward = owner->speed;
	forward.Normalize();
	float3 midTestPos = pos + forward * 121;

	std::vector<CUnit*> others = qf->GetUnitsExact(midTestPos, 115);
	float dist = 200;

	if (lastColWarning) {
		DeleteDeathDependence(lastColWarning);
		lastColWarning = 0;
		lastColWarningType = 0;
	}

	for (std::vector<CUnit*>::iterator ui = others.begin(); ui != others.end(); ++ui) {
		if (*ui == owner || !(*ui)->unitDef->canfly)
			continue;

		SyncedFloat3& op = (*ui)->midPos;
		float3 dif = op - pos;
		float3 forwardDif = forward * (forward.dot(dif));

		if (forwardDif.SqLength() < dist * dist) {
			float frontLength = forwardDif.Length();
			float3 ortoDif = dif - forwardDif;
			// note: the radius is multiplied by two since we rely on aircraft
			// having small spheres (see unitloader)
			float minOrtoDif = ((*ui)->radius + owner->radius) * 2 + frontLength * 0.05f + 5;

			if (ortoDif.SqLength() < minOrtoDif * minOrtoDif) {
				dist = frontLength;
				lastColWarning = (*ui);
			}
		}
	}
	if (lastColWarning) {
		lastColWarningType = 2;
		AddDeathDependence(lastColWarning);
		return;
	}
	for (std::vector<CUnit*>::iterator ui = others.begin(); ui != others.end(); ++ui) {
		if (*ui == owner)
			continue;
		if (((*ui)->midPos - pos).SqLength() < dist * dist) {
			lastColWarning = *ui;
		}
	}
	if (lastColWarning) {
		lastColWarningType = 1;
		AddDeathDependence(lastColWarning);
	}
	return;
}
コード例 #15
0
void UnitGroup::UnitDestroyed (aiUnit *unit)
{
	ForceUnit *fu = dynamic_cast<ForceUnit*>(unit);
	assert (fu);

	DeleteDeathDependence (fu);
	units.erase (fu);
    delete fu;
}
コード例 #16
0
void CSelectedUnitsHandler::RemoveUnit(CUnit* unit)
{
	if (selectedUnits.erase(unit))
		DeleteDeathDependence(unit, DEPENDENCE_SELECTED);
	selectionChanged = true;
	possibleCommandsChanged = true;
	selectedGroup = -1;
	unit->isSelected = false;
}
コード例 #17
0
void CWeapon::HoldFire()
{
	if (targetUnit) {
		DeleteDeathDependence(targetUnit, DEPENDENCE_TARGETUNIT);
		targetUnit = NULL;
	}
	targetType = Target_None;
	haveUserTarget = false;
}
コード例 #18
0
void CWaitCommandsAI::SquadWait::Update()
{
	if (buildUnits.empty() && ((int)waitUnits.size() < squadCount)) {
		// FIXME -- unblock remaining waitUnits ?
		delete this;
		return;
	}

	if ((int)waitUnits.size() >= squadCount) {
		CUnitSet unblockSet;
		CUnitSet::iterator it = waitUnits.begin();
		while (it != waitUnits.end()) {
			WaitState state = GetWaitState(*it);
			if (state == Active) {
				unblockSet.insert(*it);
				if ((int)unblockSet.size() >= squadCount) {
					break; // we've got our squad
				}
			}
			else if (state == Queued) {
				// do nothing
			}
			else if (state == Missing) {
				DeleteDeathDependence(*it);
				it = RemoveUnitFromSet(it, waitUnits);
				continue;
			}
			++it;
		}

		if ((int)unblockSet.size() >= squadCount) {
			// FIXME -- rebuild the order queue so
			//          that formations are created?
			SendWaitCommand(unblockSet);
			for (it = unblockSet.begin(); it != unblockSet.end(); ++it) {
				DeleteDeathDependence(*it);
				waitUnits.erase(*it);
			}
		}
	}

	UpdateText();
	// FIXME -- clean builders
}
コード例 #19
0
ファイル: Unit.cpp プロジェクト: genxinzou/svn-spring-archive
void CUnit::SetLastAttacker(CUnit* attacker)
{
    lastAttack=gs->frameNum;
    if(lastAttacker && lastAttacker!=userTarget)
        DeleteDeathDependence(lastAttacker);

    lastAttacker=attacker;
    if(attacker)
        AddDeathDependence(attacker);
}
コード例 #20
0
ファイル: SelectedUnits.cpp プロジェクト: atamanokuklu/spring
void CSelectedUnits::RemoveUnit(CUnit* unit)
{
	GML_RECMUTEX_LOCK(sel); // RemoveUnit

	if (selectedUnits.erase(unit))
		DeleteDeathDependence(unit, DEPENDENCE_SELECTED);
	selectionChanged = true;
	possibleCommandsChanged = true;
	selectedGroup = -1;
	unit->isSelected = false;
}
コード例 #21
0
ファイル: SelectedUnits.cpp プロジェクト: Gepard/spring
void CSelectedUnits::RemoveUnit(CUnit* unit)
{
	GML_RECMUTEX_LOCK(sel); // RemoveUnit

	selectedUnits.erase(unit);
	DeleteDeathDependence(unit);
	selectionChanged=true;
	possibleCommandsChanged=true;
	selectedGroup=-1;
	unit->commandAI->selected=false;
}
コード例 #22
0
void CSelectedUnitsHandler::ClearSelected()
{
	for (CUnit* u: selectedUnits) {
		u->isSelected = false;
		DeleteDeathDependence(u, DEPENDENCE_SELECTED);
	}

	selectedUnits.clear();
	selectionChanged = true;
	possibleCommandsChanged = true;
	selectedGroup = -1;
}
コード例 #23
0
void CSelectedUnits::RemoveUnit(CUnit* unit)
{
	selectedUnits.erase(unit);
	DeleteDeathDependence(unit);
	selectionChanged=true;
	possibleCommandsChanged=true;
	selectedGroup=-1;
	PUSH_CODE_MODE;
	ENTER_MIXED;
	unit->commandAI->selected=false;
	POP_CODE_MODE;
}
コード例 #24
0
void CCommandAI::SlowUpdate()
{
	if(commandQue.empty())
		return;

	Command& c=commandQue.front();

	switch(c.id){
	case CMD_WAIT:
		break;
	case CMD_STOP:{
		owner->AttackUnit(0,true);
		std::vector<CWeapon*>::iterator wi;
		for(wi=owner->weapons.begin();wi!=owner->weapons.end();++wi)
			(*wi)->HoldFire();
		FinishCommand();
		break;};
	case CMD_ATTACK:
	case CMD_DGUN:
		if(inCommand){
			if(targetDied || (c.params.size() == 1 && uh->units[int(c.params[0])] && !(uh->units[int(c.params[0])]->losStatus[owner->allyteam] & LOS_INRADAR))){
				FinishCommand();
				break;
			}
			if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
				FinishCommand();
				break;
			}
		} else {
			if(c.params.size()==1){
				if(uh->units[int(c.params[0])]!=0 && uh->units[int(c.params[0])]!=owner){
					owner->AttackUnit(uh->units[int(c.params[0])], c.id==CMD_DGUN);
					if(orderTarget)
						DeleteDeathDependence(orderTarget);
					orderTarget=uh->units[int(c.params[0])];
					AddDeathDependence(orderTarget);
					inCommand=true;
				} else {
					FinishCommand();
				}
			} else {
				float3 pos(c.params[0],c.params[1],c.params[2]);
				owner->AttackGround(pos, c.id==CMD_DGUN);
				inCommand=true;
			}
		}
		break;
	default:
		FinishCommand();
		break;
	}
}
コード例 #25
0
ファイル: Unit.cpp プロジェクト: genxinzou/svn-spring-archive
void CUnit::SetLastAttacker(CUnit* attacker)
{
	if(gs->Ally(team, attacker->team)){
		return;
	}
	if(lastAttacker && lastAttacker!=userTarget)
		DeleteDeathDependence(lastAttacker);

	lastAttack=gs->frameNum;
	lastAttacker=attacker;
	if(attacker)
		AddDeathDependence(attacker);
}
コード例 #26
0
ファイル: Unit.cpp プロジェクト: genxinzou/svn-spring-archive
void CUnit::SetUserTarget(CUnit* target)
{
    if(userTarget && lastAttacker!=userTarget)
        DeleteDeathDependence(userTarget);

    userTarget=target;
    for(vector<CWeapon*>::iterator wi=weapons.begin(); wi!=weapons.end(); ++wi)
        (*wi)->haveUserTarget=false;

    if(target) {
        AddDeathDependence(target);
    }
}
コード例 #27
0
void CFactory::StopBuild()
{
	cob->Call("StopBuilding");
	if(curBuild){
		if(curBuild->beingBuilt){
			AddMetal(curBuild->metalCost*curBuild->buildProgress);
			uh->DeleteUnit(curBuild);
		}
		DeleteDeathDependence(curBuild);
	}
	curBuild=0;
	quedBuild=false;
}
コード例 #28
0
void CWaitCommandsAI::DeathWait::Update()
{
	if (waitUnits.empty()) {
		delete this;
		return;
	}

	unitPos.clear();

	if (!deathUnits.empty()) {
		return; // more must die
	}

	CUnitSet unblockSet;
	CUnitSet::iterator it = waitUnits.begin();
	while (it != waitUnits.end()) {
		WaitState state = GetWaitState(*it);
		if (state == Active) {
			unblockSet.insert(*it);
			DeleteDeathDependence(*it);
			it = RemoveUnitFromSet(it, waitUnits);
			continue;
		}
		else if (state == Queued) {
			// do nothing
		}
		else if (state == Missing) {
			DeleteDeathDependence(*it);
			it = RemoveUnitFromSet(it, waitUnits);
			continue;
		}
		++it;
	}
	SendWaitCommand(unblockSet);
	if (waitUnits.empty()) {
		delete this;
		return;
	}
}
コード例 #29
0
ファイル: Factory.cpp プロジェクト: eXLabT/spring
void CFactory::StopBuild()
{
	// cancel a build-in-progress
	script->StopBuilding();
	if (curBuild) {
		if (curBuild->beingBuilt) {
			AddMetal(curBuild->metalCost * curBuild->buildProgress, false);
			curBuild->KillUnit(false, true, NULL);
		}
		DeleteDeathDependence(curBuild);
	}
	curBuild = 0;
	quedBuild = false;
}
コード例 #30
0
void CAirCAI::ExecuteAreaAttack(Command &c)
{
	assert(owner->unitDef->canAttack);
	CAirMoveType* myPlane = (CAirMoveType*) owner->moveType;
	if(targetDied){
		targetDied = false;
		inCommand = false;
	}
	const float3 pos(c.params[0], c.params[1], c.params[2]);
	const float radius = c.params[3];
	if(inCommand){
		if(myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDED)
			inCommand = false;
		if(orderTarget && orderTarget->pos.distance2D(pos) > radius){
			inCommand = false;
			DeleteDeathDependence(orderTarget);
			orderTarget = 0;
		}
		if (owner->commandShotCount > 0) {
			if ((c.params.size() == 4) && (commandQue.size() > 1)) {
				owner->AttackUnit(0, true);
				FinishCommand();
			}
			else if (owner->userAttackGround) {
				// reset the attack position after each run
				float3 attackPos = pos + (gs->randVector() * radius);
				attackPos.y = ground->GetHeight(attackPos.x, attackPos.z);
				owner->AttackGround(attackPos, false);
				owner->commandShotCount = 0;
			}
		}
	} else {
		owner->commandShotCount = -1;
		if(myPlane->aircraftState != CAirMoveType::AIRCRAFT_LANDED){
			inCommand = true;
			std::vector<int> eu;
			helper->GetEnemyUnits(pos, radius, owner->allyteam, eu);
			if(eu.empty()){
				float3 attackPos = pos + gs->randVector() * radius;
				attackPos.y = ground->GetHeight(attackPos.x, attackPos.z);
				owner->AttackGround(attackPos, false);
			} else {
				int num = (int) (gs->randFloat() * eu.size());
				orderTarget = uh->units[eu[num]];
				owner->AttackUnit(orderTarget, false);
				AddDeathDependence(orderTarget);
			}
		}
	}
}