Example #1
0
void CMobileCAI::SlowUpdate()
{
	if(gs->paused) // Commands issued may invoke SlowUpdate when paused
		return;
	bool wantToLand = false;
	if (dynamic_cast<AAirMoveType*>(owner->moveType)) {
		wantToLand = LandRepairIfNeeded();
		if (!wantToLand && owner->unitDef->maxFuel > 0) {
			wantToLand = RefuelIfNeeded();
		}
	}


	if (!commandQue.empty() && commandQue.front().timeOut < gs->frameNum) {
		StopMove();
		FinishCommand();
		return;
	}

	if (commandQue.empty()) {
		IdleCheck();

		//the attack order could terminate directly and thus cause a loop
		if(commandQue.empty() || commandQue.front().id == CMD_ATTACK) {
			return;
		}
	}

	// treat any following CMD_SET_WANTED_MAX_SPEED commands as options
	// to the current command  (and ignore them when it's their turn)
	if (commandQue.size() >= 2 && !slowGuard) {
		CCommandQueue::iterator it = commandQue.begin();
		it++;
		const Command& c = *it;
		if ((c.id == CMD_SET_WANTED_MAX_SPEED) && (c.params.size() >= 1)) {
			const float defMaxSpeed = owner->maxSpeed;
			const float newMaxSpeed = std::min(c.params[0], defMaxSpeed);
			if (newMaxSpeed > 0)
				owner->moveType->SetMaxSpeed(newMaxSpeed);
		}
	}

	Execute();
}
void CMobileCAI::SlowUpdate()
{
	if(owner->unitDef->maxFuel>0 && dynamic_cast<CTAAirMoveType*>(owner->moveType)){
		CTAAirMoveType* myPlane=(CTAAirMoveType*)owner->moveType;
		if(myPlane->reservedPad){
			return;
		} else {
			if(owner->currentFuel <= 0){
				StopMove();
				owner->userAttackGround=false;
				owner->userTarget=0;
				inCommand=false;
				CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
				if(lp){
					myPlane->AddDeathDependence(lp);
					myPlane->reservedPad=lp;
					myPlane->padStatus=0;
					myPlane->oldGoalPos=myPlane->goalPos;
					return;
				}
				float3 landingPos = airBaseHandler->FindClosestAirBasePos(owner,8000,owner->unitDef->minAirBasePower);
				if(landingPos != ZeroVector && owner->pos.distance2D(landingPos) > 300){
					inCommand=false;
					StopMove();
					SetGoal(landingPos,owner->pos);
				} else {
					if(myPlane->aircraftState == CTAAirMoveType::AIRCRAFT_FLYING)
						myPlane->SetState(CTAAirMoveType::AIRCRAFT_LANDING);	
				}
				return;
			}
			if(owner->currentFuel < myPlane->repairBelowHealth*owner->unitDef->maxFuel){
				if(commandQue.empty() || commandQue.front().id==CMD_PATROL){
					CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
					if(lp){
						StopMove();
						owner->userAttackGround=false;
						owner->userTarget=0;
						inCommand=false;
						myPlane->AddDeathDependence(lp);
						myPlane->reservedPad=lp;
						myPlane->padStatus=0;
						myPlane->oldGoalPos=myPlane->goalPos;
						if(myPlane->aircraftState==CTAAirMoveType::AIRCRAFT_LANDED){
							myPlane->SetState(CTAAirMoveType::AIRCRAFT_TAKEOFF);
						}
						return;
					}
				}
			}
		}
	}

	if(!commandQue.empty() && commandQue.front().timeOut < gs->frameNum){
		StopMove();
		FinishCommand();
		return;
	}

	if(commandQue.empty()) {
//		if(!owner->ai || owner->ai->State() != CHasState::Active) {
			IdleCheck();
//		}
		//the attack order could terminate directly and thus cause a loop
		if(commandQue.empty() || commandQue.front().id == CMD_ATTACK) {
			return;
		}
	}

	const float3& curPos=owner->pos;
	
	// treat any following CMD_SET_WANTED_MAX_SPEED commands as options
	// to the current command  (and ignore them when it's their turn
	if (commandQue.size() >= 2 && !slowGuard) {
		deque<Command>::iterator it = commandQue.begin();
		it++;
		const Command& c = *it;
		if ((c.id == CMD_SET_WANTED_MAX_SPEED) && (c.params.size() >= 1)) {
			const float defMaxSpeed = owner->maxSpeed;
			const float newMaxSpeed = min(c.params[0], defMaxSpeed);
			owner->moveType->SetMaxSpeed(newMaxSpeed);
		}
	}
	return Execute();
}
void CMobileCAI::SlowUpdate()
{
	if(owner->unitDef->maxFuel>0 && dynamic_cast<CTAAirMoveType*>(owner->moveType)){
		CTAAirMoveType* myPlane=(CTAAirMoveType*)owner->moveType;
		if(myPlane->reservedPad){
			return;
		} else {
			if(owner->currentFuel <= 0){
				StopMove();
				owner->userAttackGround=false;
				owner->userTarget=0;
				inCommand=false;
				CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
				if(lp){
					myPlane->AddDeathDependence(lp);
					myPlane->reservedPad=lp;
					myPlane->padStatus=0;
					myPlane->oldGoalPos=myPlane->goalPos;
					return;
				}
				float3 landingPos = airBaseHandler->FindClosestAirBasePos(owner,8000,owner->unitDef->minAirBasePower);
				if(landingPos != ZeroVector && owner->pos.distance2D(landingPos) > 300){
					inCommand=false;
					StopMove();
					SetGoal(landingPos,owner->pos);
				} else {
					if(myPlane->aircraftState == CTAAirMoveType::AIRCRAFT_FLYING)
						myPlane->SetState(CTAAirMoveType::AIRCRAFT_LANDING);	
				}
				return;
			}
			if(owner->currentFuel < myPlane->repairBelowHealth*owner->unitDef->maxFuel){
				if(commandQue.empty() || commandQue.front().id==CMD_PATROL){
					CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
					if(lp){
						StopMove();
						owner->userAttackGround=false;
						owner->userTarget=0;
						inCommand=false;
						myPlane->AddDeathDependence(lp);
						myPlane->reservedPad=lp;
						myPlane->padStatus=0;
						myPlane->oldGoalPos=myPlane->goalPos;
						if(myPlane->aircraftState==CTAAirMoveType::AIRCRAFT_LANDED){
							myPlane->SetState(CTAAirMoveType::AIRCRAFT_TAKEOFF);
						}
						return;
					}		
				}
			}
		}
	}

	if(!commandQue.empty() && commandQue.front().timeOut<gs->frameNum){
		StopMove();
		FinishCommand();
		return;
	}

	if(commandQue.empty()) {
//		if(!owner->ai || owner->ai->State() != CHasState::Active) {
			IdleCheck();
//		}
		if(commandQue.empty() || commandQue.front().id==CMD_ATTACK)	//the attack order could terminate directly and thus cause a loop
			return;
	}

	float3 curPos=owner->pos;
	
	// treat any following CMD_SET_WANTED_MAX_SPEED commands as options
	// to the current command  (and ignore them when it's their turn)
	if (commandQue.size() >= 2) {
		deque<Command>::iterator it = commandQue.begin();
		it++;
		const Command& c = *it;
		if ((c.id == CMD_SET_WANTED_MAX_SPEED) && (c.params.size() >= 1)) {
			const float defMaxSpeed = owner->maxSpeed;
			const float newMaxSpeed = min(c.params[0], defMaxSpeed);
			owner->moveType->SetMaxSpeed(newMaxSpeed);
		}
	}	 

	Command& c=commandQue.front();
	switch(c.id){
	case CMD_WAIT:{
		break;
	}
	case CMD_STOP:{
		StopMove();
		CCommandAI::SlowUpdate();
		break;
	}
	case CMD_SET_WANTED_MAX_SPEED:{
	  if (repeatOrders && (commandQue.size() >= 2) &&
	      (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
	  	commandQue.push_back(commandQue.front());
		}
		commandQue.pop_front();
		SlowUpdate();
		break;
	}
	case CMD_MOVE:{
		float3 pos(c.params[0],c.params[1],c.params[2]);
		if(!(pos==goalPos)){
			SetGoal(pos,curPos);
		}
		if((curPos-goalPos).SqLength2D()<1024 || owner->moveType->progressState==CMoveType::Failed){
			FinishCommand();
		}
		break;
	}
	case CMD_PATROL:{
		assert(owner->unitDef->canPatrol);
		if(c.params.size()<3){		//this shouldnt happen but anyway ...
			logOutput.Print("Error: got patrol cmd with less than 3 params on %s in mobilecai",
				owner->unitDef->humanName.c_str());
			return;
		}
		Command temp;
		temp.id = CMD_FIGHT;
		temp.params.push_back(c.params[0]);
		temp.params.push_back(c.params[1]);
		temp.params.push_back(c.params[2]);
		temp.options = c.options|INTERNAL_ORDER;
		commandQue.push_back(c);
		commandQue.pop_front();
		commandQue.push_front(temp);
		if(owner->group){
			owner->group->CommandFinished(owner->id,CMD_PATROL);
		}
		SlowUpdate();
		return;
	}
	case CMD_FIGHT:{
		assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight);
		if(tempOrder){
			inCommand = true;
			tempOrder = false;
		}
		if(c.params.size()<3){		//this shouldnt happen but anyway ...
			logOutput.Print("Error: got fight cmd with less than 3 params on %s in mobilecai",
				owner->unitDef->humanName.c_str());
			return;
		}
		if(c.params.size() >= 6){
			if(!inCommand){
				commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
			}
		} else {
			// Some hackery to make sure the line (commandPos1,commandPos2) is NOT
			// rotated (only shortened) if we reach this because the previous return
			// fight command finished by the 'if((curPos-pos).SqLength2D()<(64*64)){'
			// condition, but is actually updated correctly if you click somewhere
			// outside the area close to the line (for a new command).
			commandPos1 = ClosestPointOnLine(commandPos1, commandPos2, curPos);
			if ((curPos-commandPos1).SqLength2D()>(96*96)) {
				commandPos1 = curPos;
			}
		}
		float3 pos(c.params[0],c.params[1],c.params[2]);
		if(!inCommand){
			inCommand = true;
			commandPos2 = pos;
		}
		if(pos!=goalPos){
			SetGoal(pos,curPos);
		}

		if(owner->unitDef->canAttack && owner->fireState==2){
			float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, curPos);
			CUnit* enemy=helper->GetClosestEnemyUnit(
				curPosOnLine, owner->maxRange+100*owner->moveState*owner->moveState, owner->allyteam);
			if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)
						&& !(owner->unitDef->noChaseCategory & enemy->category) && !owner->weapons.empty()){
				Command c2;
				c2.id=CMD_ATTACK;
				c2.options=c.options|INTERNAL_ORDER;
				c2.params.push_back(enemy->id);
				PushOrUpdateReturnFight();
				commandQue.push_front(c2);
				inCommand=false;
				tempOrder=true;
				if(lastPC!=gs->frameNum){	//avoid infinite loops
					lastPC=gs->frameNum;
					SlowUpdate();
				}
				return;
			}
		}
		if((curPos-goalPos).SqLength2D()<(64*64) || owner->moveType->progressState==CMoveType::Failed){
			FinishCommand();
		}
		return;
	}
	case CMD_DGUN:
		if(uh->limitDgun && owner->unitDef->isCommander
		  && owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius){
			StopMove();
			FinishCommand();
			return;
		}
		//no break
	case CMD_ATTACK:
		assert(owner->unitDef->canAttack);
		if(tempOrder && owner->moveState<2){		//limit how far away we fly
			if(orderTarget && LinePointDist(commandPos1,commandPos2,orderTarget->pos) > 500+owner->maxRange){
				StopMove();
				FinishCommand();
				break;
			}
		}
		if(!inCommand){
			if(c.params.size()==1){
				if(uh->units[int(c.params[0])]!=0 && uh->units[int(c.params[0])]!=owner){
					float3 fix=uh->units[int(c.params[0])]->pos+owner->posErrorVector*128;
					SetGoal(fix,curPos);
					orderTarget=uh->units[int(c.params[0])];
					AddDeathDependence(orderTarget);
					inCommand=true;
				} else {
					StopMove();		//cancel keeppointingto
					FinishCommand();
					break;
				}
			} else {
				float3 pos(c.params[0],c.params[1],c.params[2]);
				SetGoal(pos,curPos);
				inCommand=true;
			}
		}
		else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
			// the trailing CMD_SET_WANTED_MAX_SPEED in a command pair does not count
			if ((commandQue.size() != 2) || (commandQue.back().id != CMD_SET_WANTED_MAX_SPEED)) {
				StopMove();
				FinishCommand();
				break;
			}
		}

		if(targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)){
			StopMove();		//cancel keeppointingto
			FinishCommand();
			break;
		}
		if(orderTarget){
			//note that we handle aircrafts slightly differently
			if((((owner->AttackUnit(orderTarget, c.id==CMD_DGUN)
					&& owner->weapons.size() > 0 
					&& owner->weapons.front()->range -
						owner->weapons.front()->relWeaponPos.Length() >
						orderTarget->pos.distance(owner->pos))
					|| dynamic_cast<CTAAirMoveType*>(owner->moveType))
					&& (owner->pos-orderTarget->pos).Length2D() <
						owner->maxRange*0.9f)
					|| (owner->pos-orderTarget->pos).SqLength2D()<1024){
				StopMove();
				owner->moveType->KeepPointingTo(orderTarget,
					min((float)(owner->losRadius*SQUARE_SIZE*2),
					owner->maxRange*0.9f), true);
			} else if((orderTarget->pos+owner->posErrorVector*128).distance2D(goalPos) > 10+orderTarget->pos.distance2D(owner->pos)*0.2f){
				float3 fix=orderTarget->pos+owner->posErrorVector*128;
				SetGoal(fix,curPos);
			}
		} else {
			float3 pos(c.params[0],c.params[1],c.params[2]);
			if((owner->AttackGround(pos,c.id==CMD_DGUN) && owner->weapons.size() > 0
					&& (owner->pos-pos).Length() < 
						owner->weapons.front()->range -
						owner->weapons.front()->relWeaponPos.Length())
					|| (owner->pos-pos).SqLength2D()<1024){
				StopMove();
				owner->moveType->KeepPointingTo(pos, owner->maxRange*0.9f, true);
			} else if(pos.distance2D(goalPos)>10){
				SetGoal(pos,curPos);
			}
		}
		break;
	case CMD_GUARD:
		assert(owner->unitDef->canGuard);
		if(int(c.params[0]) >= 0 && uh->units[int(c.params[0])] != NULL && UpdateTargetLostTimer(int(c.params[0]))){
			CUnit* guarded=uh->units[int(c.params[0])];
			if(owner->unitDef->canAttack && guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum
			  && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)){
				Command nc;
				nc.id=CMD_ATTACK;
				nc.params.push_back(guarded->lastAttacker->id);
				nc.options=c.options;
				commandQue.push_front(nc);
				SlowUpdate();
				return;
			} else {
				float3 dif=guarded->pos-curPos;
				dif.Normalize();
				float3 goal=guarded->pos-dif*(guarded->radius+owner->radius+64);
				if((goal-curPos).SqLength2D()<8000){
					StopMove();
					NonMoving();
				}else{
					if((goalPos-goal).SqLength2D()>3600)
						SetGoal(goal,curPos);
				}
			}
		} else {
			FinishCommand();
		}
		break;
	default:
		CCommandAI::SlowUpdate();
		break;
	}
}
void CMobileCAI::SlowUpdate()
{
    if(owner->unitDef->maxFuel>0 && dynamic_cast<CTAAirMoveType*>(owner->moveType)) {
        CTAAirMoveType* myPlane=(CTAAirMoveType*)owner->moveType;
        if(myPlane->reservedPad) {
            return;
        } else {
            if(owner->currentFuel <= 0) {
                StopMove();
                owner->userAttackGround=false;
                owner->userTarget=0;
                inCommand=false;
                CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
                if(lp) {
                    myPlane->AddDeathDependence(lp);
                    myPlane->reservedPad=lp;
                    myPlane->padStatus=0;
                    myPlane->oldGoalPos=myPlane->goalPos;
                    return;
                }
                float3 landingPos = airBaseHandler->FindClosestAirBasePos(owner,8000,owner->unitDef->minAirBasePower);
                if(landingPos != ZeroVector && owner->pos.distance2D(landingPos) > 300) {
                    inCommand=false;
                    StopMove();
                    SetGoal(landingPos,owner->pos);
                } else {
                    if(myPlane->aircraftState == CTAAirMoveType::AIRCRAFT_FLYING)
                        myPlane->SetState(CTAAirMoveType::AIRCRAFT_LANDING);
                }
                return;
            }
            if(owner->currentFuel < myPlane->repairBelowHealth*owner->unitDef->maxFuel) {
                if(commandQue.empty() || commandQue.front().id==CMD_PATROL) {
                    CAirBaseHandler::LandingPad* lp=airBaseHandler->FindAirBase(owner,8000,owner->unitDef->minAirBasePower);
                    if(lp) {
                        StopMove();
                        owner->userAttackGround=false;
                        owner->userTarget=0;
                        inCommand=false;
                        myPlane->AddDeathDependence(lp);
                        myPlane->reservedPad=lp;
                        myPlane->padStatus=0;
                        myPlane->oldGoalPos=myPlane->goalPos;
                        if(myPlane->aircraftState==CTAAirMoveType::AIRCRAFT_LANDED) {
                            myPlane->SetState(CTAAirMoveType::AIRCRAFT_TAKEOFF);
                        }
                        return;
                    }
                }
            }
        }
    }

    if(!commandQue.empty() && commandQue.front().timeOut<gs->frameNum) {
        StopMove();
        FinishCommand();
        return;
    }

    if(commandQue.empty()) {
//		if(!owner->ai || owner->ai->State() != CHasState::Active) {
        IdleCheck();
//		}
        if(commandQue.empty() || commandQue.front().id==CMD_ATTACK)	//the attack order could terminate directly and thus cause a loop
            return;
    }

    float3 curPos=owner->pos;

    Command& c=commandQue.front();
    switch(c.id) {
    case CMD_STOP: {
        StopMove();
        CCommandAI::SlowUpdate();
        break;
    }
    case CMD_MOVE: {
        float3 pos(c.params[0],c.params[1],c.params[2]);
        if(!(pos==goalPos)) {
            SetGoal(pos,curPos);
        }
        if((curPos-goalPos).SqLength2D()<1024 || owner->moveType->progressState==CMoveType::Failed) {
            FinishCommand();
        }
        break;
    }
    case CMD_PATROL: {
        if(c.params.size()<3) {		//this shouldnt happen but anyway ...
            info->AddLine("Error: got patrol cmd with less than 3 params on %s in mobilecai",
                          owner->unitDef->humanName.c_str());
            return;
        }
        Command temp;
        temp.id = CMD_FIGHT;
        temp.params.push_back(c.params[0]);
        temp.params.push_back(c.params[1]);
        temp.params.push_back(c.params[2]);
        temp.options = c.options|INTERNAL_ORDER;
        commandQue.push_back(c);
        commandQue.pop_front();
        commandQue.push_front(temp);
        if(owner->group) {
            owner->group->CommandFinished(owner->id,CMD_PATROL);
        }
        SlowUpdate();
        return;
    }
    case CMD_FIGHT: {
        if(tempOrder) {
            inCommand = true;
            tempOrder = false;
        }
        if(c.params.size()<3) {		//this shouldnt happen but anyway ...
            info->AddLine("Error: got fight cmd with less than 3 params on %s in mobilecai",
                          owner->unitDef->humanName.c_str());
            return;
        }
        if(c.params.size() >= 6) {
            if(!inCommand) {
                commandPos1 = float3(c.params[3],c.params[4],c.params[5]);
            }
        } else {
            commandPos1 = curPos;
        }
        float3 pos(c.params[0],c.params[1],c.params[2]);
        if(!inCommand) {
            inCommand = true;
            commandPos2 = pos;
        }
        if(pos!=goalPos) {
            SetGoal(pos,curPos);
        }

        if(owner->fireState==2) {
            CUnit* enemy=helper->GetClosestEnemyUnit(
                             curPos, owner->maxRange+100*owner->moveState*owner->moveState, owner->allyteam);
            if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater)
                    && !(owner->unitDef->noChaseCategory & enemy->category) && !owner->weapons.empty()) {	//todo: make sure they dont stray to far from path
                if(owner->moveState!=1
                        || LinePointDist(commandPos1,commandPos2,enemy->pos)
                        < 300+max(owner->maxRange, (float)owner->losRadius)) {
                    Command c2,c3;
                    c3 = this->GetReturnFight(c);
                    c2.id=CMD_ATTACK;
                    c2.options=c.options|INTERNAL_ORDER;
                    c2.params.push_back(enemy->id);
                    commandQue.push_front(c3);
                    commandQue.push_front(c2);
                    inCommand=false;
                    tempOrder=true;
                    if(lastPC!=gs->frameNum) {	//avoid infinite loops
                        lastPC=gs->frameNum;
                        SlowUpdate();
                    }
                    return;
                }
            }
        }
        if((curPos-goalPos).SqLength2D()<4096 || owner->moveType->progressState==CMoveType::Failed) {
            FinishCommand();
        }
        return;
    }
    case CMD_DGUN:
        if(uh->limitDgun && owner->unitDef->isCommander
                && owner->pos.distance(gs->Team(owner->team)->startPos)>uh->dgunRadius) {
            StopMove();
            FinishCommand();
            return;
        }
    //no break
    case CMD_ATTACK:
        if(tempOrder && owner->moveState<2) {		//limit how far away we fly
            if(orderTarget && LinePointDist(commandPos1,commandPos2,orderTarget->pos) > 500+owner->maxRange) {
                StopMove();
                FinishCommand();
                break;
            }
        }
        if(!inCommand) {
            if(c.params.size()==1) {
                if(uh->units[int(c.params[0])]!=0 && uh->units[int(c.params[0])]!=owner) {
                    float3 fix=uh->units[int(c.params[0])]->pos+owner->posErrorVector*128;
                    SetGoal(fix,curPos);
                    orderTarget=uh->units[int(c.params[0])];
                    AddDeathDependence(orderTarget);
                    inCommand=true;
                } else {
                    StopMove();		//cancel keeppointingto
                    FinishCommand();
                    break;
                }
            } else {
                float3 pos(c.params[0],c.params[1],c.params[2]);
                SetGoal(pos,curPos);
                inCommand=true;
            }
        }
        else if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) {
            StopMove();
            FinishCommand();
            break;
        }

        if(targetDied || (c.params.size() == 1 && uh->units[int(c.params[0])] && !(uh->units[int(c.params[0])]->losStatus[owner->allyteam] & LOS_INRADAR))) {
            StopMove();		//cancel keeppointingto
            FinishCommand();
            break;
        }
        if(orderTarget) {
            //note that we handle aircrafts slightly differently
            if((((owner->AttackUnit(orderTarget, c.id==CMD_DGUN) && owner->weapons.size() > 0
                    && owner->weapons.front()->range > orderTarget->pos.distance(owner->pos))
                    || dynamic_cast<CTAAirMoveType*>(owner->moveType))
                    && (owner->pos-orderTarget->pos).Length2D()<owner->maxRange*0.9)
                    || (owner->pos-orderTarget->pos).SqLength2D()<1024) {
                StopMove();
                owner->moveType->KeepPointingTo(orderTarget->pos, min((double)(owner->losRadius*SQUARE_SIZE*2), owner->maxRange*0.9), true);
            } else if((orderTarget->pos+owner->posErrorVector*128).distance2D(goalPos) > 10+orderTarget->pos.distance2D(owner->pos)*0.2) {
                float3 fix=orderTarget->pos+owner->posErrorVector*128;
                SetGoal(fix,curPos);
            }
        } else {
            float3 pos(c.params[0],c.params[1],c.params[2]);
            if((owner->AttackGround(pos,c.id==CMD_DGUN) && owner->weapons.size() > 0
                    && (owner->pos-pos).Length()< owner->weapons.front()->range) || (owner->pos-pos).SqLength2D()<1024) {
                StopMove();
                owner->moveType->KeepPointingTo(pos, owner->maxRange*0.9, true);
            } else if(pos.distance2D(goalPos)>10) {
                SetGoal(pos,curPos);
            }
        }
        break;
    case CMD_GUARD:
        if(uh->units[int(c.params[0])]!=0) {
            CUnit* guarded=uh->units[int(c.params[0])];
            if(guarded->lastAttacker && guarded->lastAttack+40<gs->frameNum
                    && (owner->hasUWWeapons || !guarded->lastAttacker->isUnderWater)) {
                Command nc;
                nc.id=CMD_ATTACK;
                nc.params.push_back(guarded->lastAttacker->id);
                nc.options=c.options;
                commandQue.push_front(nc);
                SlowUpdate();
                return;
            } else {
                float3 dif=guarded->pos-curPos;
                dif.Normalize();
                float3 goal=guarded->pos-dif*(guarded->radius+owner->radius+64);
                if((goal-curPos).SqLength2D()<8000) {
                    StopMove();
                    NonMoving();
                } else {
                    if((goalPos-goal).SqLength2D()>3600)
                        SetGoal(goal,curPos);
                }
            }
        } else {
            FinishCommand();
        }
        break;
    default:
        CCommandAI::SlowUpdate();
        break;
    }
}