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; } }