void CBuilderCAI::SlowUpdate() { if(commandQue.empty()){ CMobileCAI::SlowUpdate(); return; } Command& c=commandQue.front(); CBuilder* fac=(CBuilder*)owner; map<int,string>::iterator boi; if((boi=buildOptions.find(c.id))!=buildOptions.end()){ float radius; if(cachedRadiusId==c.id){ radius=cachedRadius; } else { radius=modelParser->LoadModel(unitDefHandler->GetUnitByName(boi->second)->model.modelpath,1,owner->team)->radius; cachedRadiusId=c.id; cachedRadius=radius; } if(inCommand){ if(building){ if(buildPos.distance2D(fac->pos)>fac->buildDistance+radius-8){ owner->moveType->StartMoving(buildPos, fac->buildDistance*0.5+radius); } else { StopMove(); owner->moveType->KeepPointingTo(buildPos, (fac->buildDistance+radius)*0.6, false); //needed since above startmoving cancels this } if(!fac->curBuild && !fac->terraforming){ building=false; StopMove(); //cancel the effect of KeepPointingTo FinishCommand(); } } else { buildPos.x=c.params[0]; buildPos.y=c.params[1]; buildPos.z=c.params[2]; if(buildPos.distance2D(fac->pos)<fac->buildDistance*0.6+radius){ StopMove(); if(uh->maxUnits>(int)gs->Team(owner->team)->units.size()){ buildRetries++; owner->moveType->KeepPointingTo(buildPos, fac->buildDistance*0.7+radius, false); if(fac->StartBuild(boi->second,buildPos) || buildRetries>20){ building=true; } else { ENTER_MIXED; if(owner->team==gu->myTeam && !(buildRetries&7)){ info->AddLine("%s: Build pos blocked",owner->unitDef->humanName.c_str()); info->SetLastMsgPos(owner->pos); } ENTER_SYNCED; helper->BuggerOff(buildPos,radius); NonMoving(); } } } else { if(owner->moveType->progressState==CMoveType::Failed){ if(++buildRetries>5){ StopMove(); FinishCommand(); } } SetGoal(buildPos,owner->pos, fac->buildDistance*0.4+radius); } } } else { //!inCommand float3 pos; pos.x=floor(c.params[0]/SQUARE_SIZE+0.5)*SQUARE_SIZE; pos.z=floor(c.params[2]/SQUARE_SIZE+0.5)*SQUARE_SIZE; pos.y=c.params[1]; CFeature* f=0; uh->TestUnitBuildSquare(pos,boi->second,f); if(f){ Command c2; c2.id=CMD_RECLAIM; c2.options=0; c2.params.push_back(f->id+MAX_UNITS); commandQue.push_front(c2); SlowUpdate(); //this assumes that the reclaim command can never return directly without having reclaimed the target } else { inCommand=true; SlowUpdate(); } } return; } switch(c.id){ case CMD_STOP: building=false; fac->StopBuild(); break; case CMD_REPAIR:{ if(c.params.size()==1){ //repair unit CUnit* unit=uh->units[(int)c.params[0]]; if(unit && unit->health<unit->maxHealth && unit!=owner){ if(unit->pos.distance2D(fac->pos)<fac->buildDistance+unit->radius-8){ StopMove(); fac->SetRepairTarget(unit); owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9+unit->radius, false); } else { if(goalPos.distance2D(unit->pos)>1) SetGoal(unit->pos,owner->pos, fac->buildDistance*0.9+unit->radius); } } else { StopMove(); FinishCommand(); } } else { //repair area float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; if(FindRepairTargetAndRepair(pos,radius,c.options,false)){ inCommand=false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } return;} case CMD_CAPTURE:{ if(c.params.size()==1){ //capture unit CUnit* unit=uh->units[(int)c.params[0]]; if(unit && unit->team!=owner->team){ if(unit->pos.distance2D(fac->pos)<fac->buildDistance+unit->radius-8){ StopMove(); fac->SetCaptureTarget(unit); owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9+unit->radius, false); } else { if(goalPos.distance2D(unit->pos)>1) SetGoal(unit->pos,owner->pos, fac->buildDistance*0.9+unit->radius); } } else { StopMove(); FinishCommand(); } } else { //capture area float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; if(FindCaptureTargetAndCapture(pos,radius,c.options)){ inCommand=false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } return;} case CMD_GUARD:{ CUnit* guarded=uh->units[(int)c.params[0]]; if(guarded && guarded!=owner){ if(CBuilder* b=dynamic_cast<CBuilder*>(guarded)){ if(b->terraforming){ if(fac->pos.distance2D(b->terraformCenter)<fac->buildDistance*0.8+b->terraformRadius*0.7){ StopMove(); owner->moveType->KeepPointingTo(b->terraformCenter, fac->buildDistance*0.9, false); fac->HelpTerraform(b); } else { SetGoal(b->terraformCenter,fac->pos,fac->buildDistance*0.7+b->terraformRadius*0.6); } return; } if(b->curBuild){ Command nc; nc.id=CMD_REPAIR; nc.options=c.options; nc.params.push_back(b->curBuild->id); commandQue.push_front(nc); inCommand=false; // SlowUpdate(); return; } } if(CFactory* f=dynamic_cast<CFactory*>(guarded)){ if(f->curBuild){ Command nc; nc.id=CMD_REPAIR; nc.options=c.options; nc.params.push_back(f->curBuild->id); commandQue.push_front(nc); inCommand=false; // SlowUpdate(); return; } } float3 curPos=owner->pos; float3 dif=guarded->pos-curPos; dif.Normalize(); float3 goal=guarded->pos-dif*(fac->buildDistance-5); if((guarded->pos-curPos).SqLength2D()<(fac->buildDistance*0.9+guarded->radius)*(fac->buildDistance*0.9+guarded->radius)){ StopMove(); // info->AddLine("should point with type 3?"); owner->moveType->KeepPointingTo(guarded->pos, fac->buildDistance*0.9+guarded->radius, false); if(guarded->health<guarded->maxHealth) fac->SetRepairTarget(guarded); else NonMoving(); }else{ if((goalPos-goal).SqLength2D()>4000) SetGoal(goal,curPos); } } else { FinishCommand(); } return;} case CMD_RECLAIM:{ if(c.params.size()==1){ int id=(int) c.params[0]; if(id>=MAX_UNITS){ //reclaim feature CFeature* feature=featureHandler->features[id-MAX_UNITS]; if(feature){ if(feature->pos.distance2D(fac->pos)<fac->buildDistance*0.9+feature->radius){ StopMove(); owner->moveType->KeepPointingTo(feature->pos, fac->buildDistance*0.9+feature->radius, false); fac->SetReclaimTarget(feature); } else { if(goalPos.distance2D(feature->pos)>1){ SetGoal(feature->pos,owner->pos, fac->buildDistance*0.8+feature->radius); } else { if(owner->moveType->progressState==CMoveType::Failed){ StopMove(); FinishCommand(); } } } } else { StopMove(); FinishCommand(); } } else { //reclaim unit CUnit* unit=uh->units[id]; if(unit && unit!=owner){ if(unit->pos.distance2D(fac->pos)<fac->buildDistance-1+unit->radius){ StopMove(); owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9+unit->radius, false); fac->SetReclaimTarget(unit); } else { if(goalPos.distance2D(unit->pos)>1){ SetGoal(unit->pos,owner->pos); }else{ if(owner->moveType->progressState==CMoveType::Failed){ StopMove(); FinishCommand(); } } } } else { FinishCommand(); } } } else if(c.params.size()==4){//area reclaim float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; if(FindReclaimableFeatureAndReclaim(pos,radius,c.options)){ inCommand=false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } else { //wrong number of parameters FinishCommand(); } return;} case CMD_RESURRECT:{ if(c.params.size()==1){ int id=(int)c.params[0]; if(id>=MAX_UNITS){ //resurrect feature CFeature* feature=featureHandler->features[id-MAX_UNITS]; if(feature && feature->createdFromUnit!=""){ if(feature->pos.distance2D(fac->pos)<fac->buildDistance*0.9+feature->radius){ StopMove(); owner->moveType->KeepPointingTo(feature->pos, fac->buildDistance*0.9+feature->radius, false); fac->SetResurrectTarget(feature); } else { if(goalPos.distance2D(feature->pos)>1){ SetGoal(feature->pos,owner->pos, fac->buildDistance*0.8+feature->radius); } else { if(owner->moveType->progressState==CMoveType::Failed){ StopMove(); FinishCommand(); } } } } else { if(fac->lastResurrected && uh->units[fac->lastResurrected]){ //resurrection finished, start repair c.id=CMD_REPAIR; //kind of hackery to overwrite the current order i suppose c.params.clear(); c.params.push_back(fac->lastResurrected); c.options|=INTERNAL_ORDER; fac->lastResurrected=0; inCommand=false; SlowUpdate(); return; } StopMove(); FinishCommand(); } } else { //resurrect unit FinishCommand(); } } else if(c.params.size()==4){//area resurect float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; if(FindResurrectableFeatureAndResurrect(pos,radius,c.options)){ inCommand=false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } else { //wrong number of parameters FinishCommand(); } return;} case CMD_PATROL:{ float3 curPos=owner->pos; if(commandFromPatrol){ commandFromPatrol=false; inCommand=true; --patrolTime; //prevent searching reclaimtargets etc directly if one of those call returned directly (infinite loop) } if(!inCommand){ float3 pos(c.params[0],c.params[1],c.params[2]); inCommand=true; Command co; co.id=CMD_PATROL; co.params.push_back(curPos.x); co.params.push_back(curPos.y); co.params.push_back(curPos.z); commandQue.push_front(co); activeCommand=1; patrolTime=0; } Command& c=commandQue[activeCommand]; if(c.params.size()<3){ //this shouldnt happen but anyway ... info->AddLine("Error: got patrol cmd with less than 3 params on %s",owner->unitDef->humanName.c_str()); return; } if(!(patrolTime&3) && owner->fireState==2){ if(FindRepairTargetAndRepair(owner->pos,300*owner->moveState,c.options,true)){ commandFromPatrol=true; inCommand=false; SlowUpdate(); return; } if(FindReclaimableFeatureAndReclaim(owner->pos,300*owner->moveState,c.options)){ commandFromPatrol=true; inCommand=false; SlowUpdate(); return; } patrolGoal=float3(c.params[0],c.params[1],c.params[2]); } patrolTime++; if(!(patrolGoal==goalPos)){ SetGoal(patrolGoal,curPos); } if((curPos-float3(c.params[0],c.params[1],c.params[2])).SqLength2D()<64){ if(owner->group) owner->group->CommandFinished(owner->id,CMD_PATROL); if((int)commandQue.size()<=activeCommand+1) activeCommand=0; else { if(commandQue[activeCommand+1].id!=CMD_PATROL) activeCommand=0; else activeCommand++; } } if(owner->haveTarget) StopMove(); else owner->moveType->StartMoving(patrolGoal, 1000); return;} case CMD_RESTORE:{ if(inCommand){ if(!fac->terraforming){ FinishCommand(); } } else { float3 pos(c.params[0],c.params[1],c.params[2]); float radius(c.params[3]); if(fac->pos.distance2D(pos)<fac->buildDistance-1){ StopMove(); fac->StartRestore(pos,radius); owner->moveType->KeepPointingTo(pos, fac->buildDistance*0.9, false); inCommand=true; } else { SetGoal(pos,owner->pos, fac->buildDistance*0.9); } } return;} default: break; } CMobileCAI::SlowUpdate(); }
void CFactoryCAI::GiveCommandReal(const Command& c, bool fromSynced) { const int cmdID = c.GetID(); // move is always allowed for factories (passed to units it produces) if (cmdID == CMD_SET_WANTED_MAX_SPEED) return; if ((cmdID != CMD_MOVE) && !AllowedCommand(c, fromSynced)) return; auto boi = buildOptions.find(cmdID); // not a build order (or a build order we do not support, eg. if multiple // factories of different types were selected) so queue it to built units if (boi == buildOptions.end()) { if (cmdID < 0) return; if (nonQueingCommands.find(cmdID) != nonQueingCommands.end()) { CCommandAI::GiveAllowedCommand(c); return; } if (cmdID == CMD_INSERT || cmdID == CMD_REMOVE) { CCommandAI::GiveAllowedCommand(c); return; } if (!(c.options & SHIFT_KEY) && (cmdID == CMD_WAIT || cmdID == CMD_SELFD)) { CCommandAI::GiveAllowedCommand(c); return; } if (!(c.options & SHIFT_KEY)) { waitCommandsAI.ClearUnitQueue(owner, newUnitCommands); CCommandAI::ClearCommandDependencies(); newUnitCommands.clear(); } CCommandAI::AddCommandDependency(c); if (cmdID != CMD_STOP) { if ((cmdID == CMD_WAIT) || (cmdID == CMD_SELFD)) { if (!newUnitCommands.empty() && (newUnitCommands.back().GetID() == cmdID)) { if (cmdID == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_back(); } else { newUnitCommands.push_back(c); } } else { bool dummy; if (CancelCommands(c, newUnitCommands, dummy) > 0) { return; } else { if (GetOverlapQueued(c, newUnitCommands).empty()) { newUnitCommands.push_back(c); } else { return; } } } } // the first new-unit build order can not be WAIT or SELFD while (!newUnitCommands.empty()) { const Command& newUnitCommand = newUnitCommands.front(); const int id = newUnitCommand.GetID(); if ((id == CMD_WAIT) || (id == CMD_SELFD)) { if (cmdID == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_front(); } else { break; } } return; } int& numQueued = boi->second; int numItems = 1; if (c.options & SHIFT_KEY) { numItems *= 5; } if (c.options & CONTROL_KEY) { numItems *= 20; } if (c.options & RIGHT_MOUSE_KEY) { numQueued -= numItems; numQueued = std::max(numQueued, 0); int numToErase = numItems; if (c.options & ALT_KEY) { for (unsigned int cmdNum = 0; cmdNum < commandQue.size() && numToErase; ++cmdNum) { if (commandQue[cmdNum].GetID() == cmdID) { commandQue[cmdNum] = Command(CMD_STOP); numToErase--; } } } else { for (int cmdNum = commandQue.size() - 1; cmdNum != -1 && numToErase; --cmdNum) { if (commandQue[cmdNum].GetID() == cmdID) { commandQue[cmdNum] = Command(CMD_STOP); numToErase--; } } } UpdateIconName(cmdID, numQueued); SlowUpdate(); } else { if (c.options & ALT_KEY) { for (int a = 0; a < numItems; ++a) { if (repeatOrders) { Command nc(c); nc.options |= INTERNAL_ORDER; if (commandQue.empty()) { commandQue.push_front(nc); } else { commandQue.insert(commandQue.begin()+1, nc); } } else { commandQue.push_front(c); } } if (!repeatOrders) { CFactory* fac = static_cast<CFactory*>(owner); fac->StopBuild(); } } else { for (int a = 0; a < numItems; ++a) { commandQue.push_back(c); } } numQueued += numItems; UpdateIconName(cmdID, numQueued); SlowUpdate(); } }
void CBuilderCAI::ExecuteReclaim(Command& c) { // not all builders are reclaim-capable by default if (!owner->unitDef->canReclaim) return; if (c.params.size() == 1 || c.params.size() == 5) { const int signedId = (int) c.params[0]; if (signedId < 0) { LOG_L(L_WARNING, "Trying to reclaim unit or feature with id < 0 (%i), aborting.", signedId); return; } const unsigned int uid = signedId; const bool checkForBetterTarget = ((++randomCounter % 5) == 0); if (checkForBetterTarget && (c.options & INTERNAL_ORDER) && (c.params.size() >= 5)) { // regular check if there is a closer reclaim target CSolidObject* obj; if (uid >= unitHandler->MaxUnits()) { obj = featureHandler->GetFeature(uid - unitHandler->MaxUnits()); } else { obj = unitHandler->GetUnit(uid); } if (obj) { const float3& pos = c.GetPos(1); const float radius = c.params[4]; const float curdist = pos.SqDistance2D(obj->pos); const bool recUnits = !!(c.options & META_KEY); const bool recEnemyOnly = (c.options & META_KEY) && (c.options & CONTROL_KEY); const bool recSpecial = !!(c.options & CONTROL_KEY); ReclaimOption recopt = REC_NORESCHECK; if (recUnits) recopt |= REC_UNITS; if (recEnemyOnly) recopt |= REC_ENEMYONLY; if (recSpecial) recopt |= REC_SPECIAL; const int rid = FindReclaimTarget(pos, radius, c.options, recopt, curdist); if ((rid > 0) && (rid != uid)) { FinishCommand(); RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); return; } } } if (uid >= unitHandler->MaxUnits()) { // reclaim feature CFeature* feature = featureHandler->GetFeature(uid - unitHandler->MaxUnits()); if (feature != NULL) { bool featureBeingResurrected = IsFeatureBeingResurrected(feature->id, owner); featureBeingResurrected &= (c.options & INTERNAL_ORDER) && !(c.options & CONTROL_KEY); if (featureBeingResurrected || !ReclaimObject(feature)) { StopMove(); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); } else { AddUnitToFeatureReclaimers(owner); } } else { StopMove(); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); } RemoveUnitFromReclaimers(owner); } else { // reclaim unit CUnit* unit = unitHandler->GetUnit(uid); if (unit != NULL && c.params.size() == 5) { const float3& pos = c.GetPos(1); const float radius = c.params[4] + 100.0f; // do not walk too far outside reclaim area const bool outOfReclaimRange = (pos.SqDistance2D(unit->pos) > radius * radius) || (ownerBuilder->curReclaim == unit && unit->IsMoving() && !IsInBuildRange(unit)); const bool busyAlliedBuilder = unit->unitDef->builder && !unit->commandAI->commandQue.empty() && teamHandler->Ally(owner->allyteam, unit->allyteam); if (outOfReclaimRange || busyAlliedBuilder) { StopMove(); RemoveUnitFromReclaimers(owner); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); return; } } if (unit != NULL && unit != owner && unit->unitDef->reclaimable && UpdateTargetLostTimer(unit->id) && unit->AllowedReclaim(owner)) { if (!ReclaimObject(unit)) { StopMove(); FinishCommand(); } else { AddUnitToReclaimers(owner); } } else { RemoveUnitFromReclaimers(owner); FinishCommand(); } RemoveUnitFromFeatureReclaimers(owner); } } else if (c.params.size() == 4) { // area reclaim const float3 pos = c.GetPos(0); const float radius = c.params[3]; const bool recUnits = !!(c.options & META_KEY); const bool recEnemyOnly = (c.options & META_KEY) && (c.options & CONTROL_KEY); const bool recSpecial = !!(c.options & CONTROL_KEY); RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); ownerBuilder->StopBuild(); ReclaimOption recopt = REC_NORESCHECK; if (recUnits) recopt |= REC_UNITS; if (recEnemyOnly) recopt |= REC_ENEMYONLY; if (recSpecial) recopt |= REC_SPECIAL; if (FindReclaimTargetAndReclaim(pos, radius, c.options, recopt)) { inCommand = false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } else { // wrong number of parameters RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); FinishCommand(); } }
void CAirCAI::SlowUpdate() { if(!commandQue.empty() && commandQue.front().timeOut<gs->frameNum){ FinishCommand(); return; } CAirMoveType* myPlane=(CAirMoveType*)owner->moveType; if(owner->unitDef->maxFuel>0){ if(myPlane->reservedPad){ return; }else{ if(owner->currentFuel <= 0){ 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){ if(myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDED && owner->pos.distance2D(landingPos) > 800) myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF); myPlane->goalPos=landingPos; } else { if(myPlane->aircraftState == CAirMoveType::AIRCRAFT_FLYING) myPlane->SetState(CAirMoveType::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){ owner->userAttackGround=false; owner->userTarget=0; inCommand=false; myPlane->AddDeathDependence(lp); myPlane->reservedPad=lp; myPlane->padStatus=0; myPlane->oldGoalPos=myPlane->goalPos; if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_LANDED){ myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF); } return; } } } } } if(commandQue.empty()){ if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_FLYING && !owner->unitDef->DontLand ()) myPlane->SetState(CAirMoveType::AIRCRAFT_LANDING); if(owner->unitDef->canAttack && owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){ if(myPlane->isFighter){ float testRad=1000*owner->moveState; CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam); if(enemy && !enemy->crashing){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=0; commandQue.push_front(nc); inCommand=false; return; } } float testRad=500*owner->moveState; CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam); if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && !enemy->crashing && (myPlane->isFighter || !enemy->unitDef->canfly)){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=0; commandQue.push_front(nc); inCommand=false; return; } } return; } Command& c = commandQue.front(); if (c.id == CMD_WAIT) { if ((myPlane->aircraftState == CAirMoveType::AIRCRAFT_FLYING) && !owner->unitDef->DontLand()) { myPlane->SetState(CAirMoveType::AIRCRAFT_LANDING); } return; } if (c.id != CMD_STOP) { if (myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDED) { myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF); } if (myPlane->aircraftState == CAirMoveType::AIRCRAFT_LANDING) { myPlane->SetState(CAirMoveType::AIRCRAFT_FLYING); } } float3 curPos=owner->pos; switch(c.id){ case CMD_STOP:{ CCommandAI::SlowUpdate(); break; } case CMD_MOVE:{ if(tempOrder){ tempOrder=false; inCommand=true; } if(!inCommand){ inCommand=true; commandPos1=myPlane->owner->pos; } float3 pos(c.params[0],c.params[1],c.params[2]); commandPos2=pos; myPlane->goalPos=pos; if(owner->unitDef->canAttack && !(c.options&CONTROL_KEY)){ if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){ if(myPlane->isFighter){ float testRad=500*owner->moveState; CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*20,testRad,owner->allyteam); if(enemy && ((enemy->unitDef->canfly && !enemy->crashing && myPlane->isFighter) || (!enemy->unitDef->canfly && (!myPlane->isFighter || owner->moveState==2)))){ if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options; commandQue.push_front(nc); tempOrder=true; inCommand=false; SlowUpdate(); return; } } } if((!myPlane->isFighter || owner->moveState==2) && owner->maxRange>0){ float testRad=325*owner->moveState; CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*30,testRad,owner->allyteam); if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && ((enemy->unitDef->canfly && !enemy->crashing && myPlane->isFighter) || (!enemy->unitDef->canfly && (!myPlane->isFighter || owner->moveState==2)))){ if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options; commandQue.push_front(nc); tempOrder=true; inCommand=false; SlowUpdate(); return; } } } } } if((curPos-pos).SqLength2D()<16000){ FinishCommand(); } break;} case CMD_PATROL:{ assert(owner->unitDef->canPatrol); float3 curPos=owner->pos; if(c.params.size()<3){ //this shouldnt happen but anyway ... logOutput.Print("Error: got patrol cmd with less than 3 params on %s in aircai", 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(); break;} case CMD_FIGHT:{ assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); if(tempOrder){ tempOrder=false; inCommand=true; } if(c.params.size()<3){ //this shouldnt happen but anyway ... logOutput.Print("Error: got fight cmd with less than 3 params on %s in AirCAI", 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()<(127*127)){' // 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()>(150*150)) { commandPos1 = curPos; } } goalPos=float3(c.params[0],c.params[1],c.params[2]); if(!inCommand){ inCommand = true; commandPos2=goalPos; } // CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway... if (owner->unitDef->canAttack && owner->fireState == 2 && owner->moveState != 0 && owner->maxRange > 0) { float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos+owner->speed*10); float testRad=1000*owner->moveState; CUnit* enemy = helper->GetClosestEnemyAircraft(curPosOnLine,testRad,owner->allyteam); if(myPlane->isFighter && enemy && !enemy->crashing && (owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,enemy->pos) < 1000)) { Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options|INTERNAL_ORDER; commandQue.push_front(nc); tempOrder=true; inCommand=false; if(lastPC1!=gs->frameNum){ //avoid infinite loops lastPC1=gs->frameNum; SlowUpdate(); } return; } else { float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos+owner->speed*20); float testRad=500*owner->moveState; enemy=helper->GetClosestEnemyUnit(curPosOnLine,testRad,owner->allyteam); if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && !enemy->crashing && (myPlane->isFighter || !enemy->unitDef->canfly)) { Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options|INTERNAL_ORDER; PushOrUpdateReturnFight(); commandQue.push_front(nc); tempOrder=true; inCommand=false; if(lastPC2!=gs->frameNum){ //avoid infinite loops lastPC2=gs->frameNum; SlowUpdate(); } return; } } } myPlane->goalPos=goalPos; if((owner->pos-goalPos).SqLength2D()<(127*127) || (owner->pos+owner->speed*8-goalPos).SqLength2D()<(127*127)){ FinishCommand(); } return;} case CMD_ATTACK: assert(owner->unitDef->canAttack); targetAge++; if(tempOrder && owner->moveState==1){ //limit how far away we fly if(orderTarget && LinePointDist(commandPos1,commandPos2,orderTarget->pos) > 1500){ owner->SetUserTarget(0); FinishCommand(); break; } } if(tempOrder && myPlane->isFighter && orderTarget){ if(owner->fireState==2 && owner->moveState!=0){ CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*50,800,owner->allyteam); if(enemy && (!orderTarget->unitDef->canfly || (orderTarget->pos-owner->pos+owner->speed*50).Length()+100*gs->randFloat()*40-targetAge < (enemy->pos-owner->pos+owner->speed*50).Length())){ c.params.clear(); c.params.push_back(enemy->id); inCommand=false; } } } if(inCommand){ if(targetDied || (c.params.size() == 1 && UpdateTargetLostTimer(int(c.params[0])) == 0)){ FinishCommand(); break; } if ((c.params.size() == 3) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) { owner->AttackUnit(0,true); FinishCommand(); break; } if(orderTarget && orderTarget->unitDef->canfly && orderTarget->crashing){ owner->SetUserTarget(0); FinishCommand(); break; } if(orderTarget){ // myPlane->goalPos=orderTarget->pos; } else { // float3 pos(c.params[0],c.params[1],c.params[2]); // myPlane->goalPos=pos; } } else { targetAge=0; if(c.params.size()==1){ if(uh->units[int(c.params[0])]!=0 && uh->units[int(c.params[0])]!=owner){ orderTarget=uh->units[int(c.params[0])]; owner->AttackUnit(orderTarget,false); AddDeathDependence(orderTarget); inCommand=true; } else { FinishCommand(); break; } } else { float3 pos(c.params[0],c.params[1],c.params[2]); owner->AttackGround(pos,false); inCommand=true; } } break; case CMD_AREA_ATTACK:{ assert(owner->unitDef->canAttack); if(targetDied){ targetDied=false; inCommand=false; } float3 pos(c.params[0],c.params[1],c.params[2]); 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 ((c.params.size() == 4) && (owner->commandShotCount > 0) && (commandQue.size() > 1)) { owner->AttackUnit(0,true); FinishCommand(); } } else { 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); } } } 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->maxRange>0 && (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 { Command c2; c2.id=CMD_MOVE; c2.options=c.options; c2.params.push_back(guarded->pos.x); c2.params.push_back(guarded->pos.y); c2.params.push_back(guarded->pos.z); c2.timeOut=gs->frameNum+60; commandQue.push_front(c2); return; } } else { FinishCommand(); } break; default: CCommandAI::SlowUpdate(); break; } }
void CCommandAI::ExecuteInsert(const Command& c, bool fromSynced) { if (c.params.size() < 3) { return; } // make the command Command newCmd((int)c.params[1], (unsigned char)c.params[2]); for (int p = 3; p < (int)c.params.size(); p++) { newCmd.params.push_back(c.params[p]); } // validate the command if (!AllowedCommand(newCmd, fromSynced)) { return; } CCommandQueue* queue = &commandQue; bool facBuildQueue = false; CFactoryCAI* facCAI = dynamic_cast<CFactoryCAI*>(this); if (facCAI) { if (c.options & CONTROL_KEY) { // check the build order const map<int, CFactoryCAI::BuildOption>& bOpts = facCAI->buildOptions; if ((newCmd.GetID() != CMD_STOP) && (newCmd.GetID() != CMD_WAIT) && ((newCmd.GetID() >= 0) || (bOpts.find(newCmd.GetID()) == bOpts.end()))) { return; } facBuildQueue = true; } else { // use the new commands queue = &facCAI->newUnitCommands; } } // FIXME: handle CMD_LOOPBACKATTACK, etc... CCommandQueue::iterator insertIt = queue->begin(); if (c.options & ALT_KEY) { // treat param0 as a position int pos = (int)c.params[0]; const unsigned int qsize = queue->size(); if (pos < 0) { pos = qsize + pos + 1; // convert the negative index if (pos < 0) { pos = 0; } } if (pos > qsize) { pos = qsize; } std::advance(insertIt, pos); } else { // treat param0 as a command tag const unsigned int tag = (unsigned int)c.params[0]; CCommandQueue::iterator ci; bool found = false; for (ci = queue->begin(); ci != queue->end(); ++ci) { const Command& qc = *ci; if (qc.tag == tag) { insertIt = ci; found = true; break; } } if (!found) { return; } if ((c.options & RIGHT_MOUSE_KEY) && (insertIt != queue->end())) { ++insertIt; // insert after the tagged command } } if (facBuildQueue) { facCAI->InsertBuildCommand(insertIt, newCmd); if (!owner->stunned) { SlowUpdate(); } return; } // shutdown the current order if the insertion is at the beginning if (!queue->empty() && (insertIt == queue->begin())) { inCommand = false; targetDied = false; unimportantMove = false; SetOrderTarget(NULL); const Command& cmd = queue->front(); eoh->CommandFinished(*owner, cmd); eventHandler.UnitCmdDone(owner, cmd.GetID(), cmd.tag); } queue->insert(insertIt, newCmd); if (!owner->stunned) { SlowUpdate(); } }
void CBuilderCAI::ExecuteRepair(Command& c) { // not all builders are repair-capable by default if (!owner->unitDef->canRepair) return; if (c.params.size() == 1 || c.params.size() == 5) { // repair unit CUnit* unit = unitHandler->GetUnit(c.params[0]); if (unit == NULL) { FinishCommand(); return; } if (tempOrder && owner->moveState <= MOVESTATE_MANEUVER) { // limit how far away we go when not roaming if (LinePointDist(commandPos1, commandPos2, unit->pos) > std::max(500.0f, GetBuildRange(unit->radius))) { StopMove(); FinishCommand(); return; } } if (c.params.size() == 5) { const float3& pos = c.GetPos(1); const float radius = c.params[4] + 100.0f; // do not walk too far outside repair area if ((pos - unit->pos).SqLength2D() > radius * radius || (unit->IsMoving() && (((c.options & INTERNAL_ORDER) && !TargetInterceptable(unit, unit->speed.Length2D())) || ownerBuilder->curBuild == unit) && !IsInBuildRange(unit))) { StopMove(); FinishCommand(); return; } } // do not consider units under construction irreparable // even if they can be repaired bool canRepairUnit = true; canRepairUnit &= ((unit->beingBuilt) || (unit->unitDef->repairable && (unit->health < unit->maxHealth))); canRepairUnit &= ((unit != owner) || owner->unitDef->canSelfRepair); canRepairUnit &= (!unit->soloBuilder || (unit->soloBuilder == owner)); canRepairUnit &= (!(c.options & INTERNAL_ORDER) || (c.options & CONTROL_KEY) || !IsUnitBeingReclaimed(unit, owner)); canRepairUnit &= (UpdateTargetLostTimer(unit->id) != 0); if (canRepairUnit) { if (MoveInBuildRange(unit)) { ownerBuilder->SetRepairTarget(unit); } } else { StopMove(); FinishCommand(); } } else if (c.params.size() == 4) { // area repair const float3 pos = c.GetPos(0); const float radius = c.params[3]; ownerBuilder->StopBuild(); if (FindRepairTargetAndRepair(pos, radius, c.options, false, (c.options & META_KEY))) { inCommand = false; SlowUpdate(); return; } if (!(c.options & ALT_KEY)) { FinishCommand(); } } else { FinishCommand(); } }
void CBuilderCAI::ExecuteGuard(Command& c) { assert(owner->unitDef->canGuard); CBuilder* fac=(CBuilder*)owner; CUnit* guarded=uh->units[(int)c.params[0]]; if (guarded && guarded!=owner && UpdateTargetLostTimer((int)c.params[0])) { if (CBuilder* b=dynamic_cast<CBuilder*>(guarded)) { if (b->terraforming) { if (f3Dist(fac->pos, b->terraformCenter) < (fac->buildDistance * 0.8f) + (b->terraformRadius * 0.7f)) { StopMove(); owner->moveType->KeepPointingTo(b->terraformCenter, fac->buildDistance*0.9f, false); fac->HelpTerraform(b); } else { StopSlowGuard(); SetGoal(b->terraformCenter,fac->pos,fac->buildDistance*0.7f+b->terraformRadius*0.6f); } return; } else if (b->curReclaim && owner->unitDef->canReclaim){ StopSlowGuard(); if(!ReclaimObject(b->curReclaim)){ StopMove(); } return; } else { fac->StopBuild(); } if (b->curBuild && (!b->curBuild->soloBuilder || (b->curBuild->soloBuilder == owner)) && (( b->curBuild->beingBuilt && owner->unitDef->canAssist) || (!b->curBuild->beingBuilt && owner->unitDef->canRepair))) { StopSlowGuard(); Command nc; nc.id=CMD_REPAIR; nc.options=c.options; nc.params.push_back(b->curBuild->id); commandQue.push_front(nc); inCommand=false; SlowUpdate(); return; } } if(CFactory* f=dynamic_cast<CFactory*>(guarded)){ if (f->curBuild && (!f->curBuild->soloBuilder || (f->curBuild->soloBuilder == owner)) && (( f->curBuild->beingBuilt && owner->unitDef->canAssist) || (!f->curBuild->beingBuilt && owner->unitDef->canRepair))) { StopSlowGuard(); Command nc; nc.id=CMD_REPAIR; nc.options=c.options; nc.params.push_back(f->curBuild->id); commandQue.push_front(nc); inCommand=false; // SlowUpdate(); return; } } if (IsUnitBeingReclaimedByFriend(guarded)) return; float3 curPos = owner->pos; float3 dif = guarded->pos - curPos; dif.Normalize(); float3 goal = guarded->pos - dif * (fac->buildDistance * 0.5f); if (f3SqLen(guarded->pos - curPos) > (fac->buildDistance*1.1f + guarded->radius) * (fac->buildDistance*1.1f + guarded->radius)) { StopSlowGuard(); } if (f3SqLen(guarded->pos - curPos) < (fac->buildDistance*0.9f + guarded->radius) * (fac->buildDistance*0.9f + guarded->radius)) { StartSlowGuard(guarded->maxSpeed); StopMove(); // logOutput.Print("should point with type 3?"); owner->moveType->KeepPointingTo(guarded->pos, fac->buildDistance*0.9f+guarded->radius, false); if ((guarded->health < guarded->maxHealth) && (!guarded->soloBuilder || (guarded->soloBuilder == owner)) && (( guarded->beingBuilt && owner->unitDef->canAssist) || (!guarded->beingBuilt && owner->unitDef->canRepair))) { StopSlowGuard(); Command nc; nc.id=CMD_REPAIR; nc.options=c.options; nc.params.push_back(guarded->id); commandQue.push_front(nc); inCommand=false; return; } else { NonMoving(); } } else { if (f3SqLen(goalPos - goal) > 4000 || f3SqLen(goalPos - owner->pos) < (owner->maxSpeed*30 + 1 + SQUARE_SIZE*2) * (owner->maxSpeed*30 + 1 + SQUARE_SIZE*2)){ SetGoal(goal,curPos); } } } else { FinishCommand(); } return; }
void CAirCAI::SlowUpdate() { if(!commandQue.empty() && commandQue.front().timeOut<gs->frameNum){ FinishCommand(); return; } CAirMoveType* myPlane=(CAirMoveType*)owner->moveType; if(commandQue.empty()){ if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_FLYING) myPlane->SetState(CAirMoveType::AIRCRAFT_LANDING); if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){ if(myPlane->isFighter){ float testRad=1000*owner->moveState; CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam); if(enemy && !enemy->crashing){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=0; commandQue.push_front(nc); inCommand=false; return; } } if(owner->moveState && owner->fireState==2 && owner->maxRange>0){ float testRad=500*owner->moveState; CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam); if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && !enemy->crashing && (myPlane->isFighter || !enemy->unitDef->canfly)){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=0; commandQue.push_front(nc); inCommand=false; return; } } } return; } if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_LANDED && commandQue.front().id!=CMD_STOP){ myPlane->SetState(CAirMoveType::AIRCRAFT_TAKEOFF); } if(myPlane->aircraftState==CAirMoveType::AIRCRAFT_LANDING && commandQue.front().id!=CMD_STOP){ myPlane->SetState(CAirMoveType::AIRCRAFT_FLYING); } float3 curPos=owner->pos; Command& c=commandQue.front(); switch(c.id){ case CMD_STOP:{ CCommandAI::SlowUpdate(); break;} case CMD_MOVE:{ if(tempOrder) tempOrder=false; float3 pos(c.params[0],c.params[1],c.params[2]); myPlane->goalPos=pos; if(!(c.options&CONTROL_KEY)){ if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){ if(myPlane->isFighter){ float testRad=500*owner->moveState; CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*20,testRad,owner->allyteam); if(enemy && ((enemy->unitDef->canfly && !enemy->crashing && myPlane->isFighter) || (!enemy->unitDef->canfly && (!myPlane->isFighter || owner->moveState==2)))){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options; commandQue.push_front(nc); tempOrder=true; inCommand=false; SlowUpdate(); return; } } if((!myPlane->isFighter || owner->moveState==2) && owner->maxRange>0){ float testRad=325*owner->moveState; CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*30,testRad,owner->allyteam); if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && ((enemy->unitDef->canfly && !enemy->crashing && myPlane->isFighter) || (!enemy->unitDef->canfly && (!myPlane->isFighter || owner->moveState==2)))){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options; commandQue.push_front(nc); tempOrder=true; inCommand=false; SlowUpdate(); return; } } } } if((curPos-pos).SqLength2D()<16000){ FinishCommand(); } break;} case CMD_PATROL:{ if(tempOrder){ tempOrder=false; inCommand=true; } if(!inCommand){ float3 pos(c.params[0],c.params[1],c.params[2]); inCommand=true; Command co; co.id=CMD_PATROL; co.params.push_back(curPos.x); co.params.push_back(curPos.y); co.params.push_back(curPos.z); commandQue.push_front(co); activeCommand=1; patrolTime=3; } Command& c=commandQue[activeCommand]; if(c.params.size()<3){ info->AddLine("Patrol command with insufficient parameters ?"); return; } goalPos=float3(c.params[0],c.params[1],c.params[2]); patrolTime++; if(owner->fireState==2 && owner->moveState!=0 && owner->maxRange>0){ if(myPlane->isFighter){ float testRad=1000*owner->moveState; CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*10,testRad,owner->allyteam); if(enemy && !enemy->crashing){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options; commandQue.push_front(nc); tempOrder=true; inCommand=false; SlowUpdate(); return; } } if((!myPlane->isFighter || owner->moveState==2) && owner->maxRange>0){ float testRad=500*owner->moveState; CUnit* enemy=helper->GetClosestEnemyUnit(owner->pos+owner->speed*20,testRad,owner->allyteam); if(enemy && (owner->hasUWWeapons || !enemy->isUnderWater) && !enemy->crashing && (myPlane->isFighter || !enemy->unitDef->canfly)){ Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options; commandQue.push_front(nc); tempOrder=true; inCommand=false; SlowUpdate(); return; } } } myPlane->goalPos=goalPos; if((owner->pos-goalPos).SqLength2D()<16000 || (owner->pos+owner->speed*8-goalPos).SqLength2D()<16000){ if(owner->group) owner->group->CommandFinished(owner->id,CMD_PATROL); if((int)commandQue.size()<=activeCommand+1) activeCommand=0; else { if(commandQue[activeCommand+1].id!=CMD_PATROL) activeCommand=0; else activeCommand++; } } return;} case CMD_ATTACK: targetAge++; if(tempOrder && myPlane->isFighter && orderTarget){ if(owner->fireState==2 && owner->moveState!=0){ CUnit* enemy=helper->GetClosestEnemyAircraft(owner->pos+owner->speed*50,800,owner->allyteam); if(enemy && (!orderTarget->unitDef->canfly || (orderTarget->pos-owner->pos+owner->speed*50).Length()+100*gs->randFloat()*40-targetAge < (enemy->pos-owner->pos+owner->speed*50).Length())){ c.params.clear(); c.params.push_back(enemy->id); inCommand=false; } } } if(inCommand){ if(targetDied){ FinishCommand(); break; } if(orderTarget && orderTarget->unitDef->canfly && orderTarget->crashing){ owner->SetUserTarget(0); FinishCommand(); break; } if(orderTarget){ // myPlane->goalPos=orderTarget->pos; } else { // float3 pos(c.params[0],c.params[1],c.params[2]); // myPlane->goalPos=pos; } } else { targetAge=0; if(c.params.size()==1){ if(uh->units[int(c.params[0])]!=0 && uh->units[int(c.params[0])]!=owner){ orderTarget=uh->units[int(c.params[0])]; owner->AttackUnit(orderTarget,false); AddDeathDependence(orderTarget); inCommand=true; } else { FinishCommand(); break; } } else { float3 pos(c.params[0],c.params[1],c.params[2]); owner->AttackGround(pos,false); inCommand=true; } } break; case CMD_AREA_ATTACK:{ if(targetDied){ targetDied=false; inCommand=false; } float3 pos(c.params[0],c.params[1],c.params[2]); 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; } } else { 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=gs->randFloat()*eu.size(); orderTarget=uh->units[eu[num]]; owner->AttackUnit(orderTarget,false); AddDeathDependence(orderTarget); } } } 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->maxRange>0 && (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 { Command c2; c2.id=CMD_MOVE; c2.options=c.options; c2.params.push_back(guarded->pos.x); c2.params.push_back(guarded->pos.y); c2.params.push_back(guarded->pos.z); c2.timeOut=gs->frameNum+60; commandQue.push_front(c2); return; } } 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((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.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; } }
void CBuilderCAI::SlowUpdate() { if (commandQue.empty()) { CMobileCAI::SlowUpdate(); return; } if (owner->stunned) { return; } CBuilder* fac = (CBuilder*)owner; Command& c = commandQue.front(); if (OutOfImmobileRange(c)) { FinishCommand(); return; } map<int, string>::iterator boi = buildOptions.find(c.id); if (!owner->beingBuilt && boi != buildOptions.end()) { const UnitDef* ud = unitDefHandler->GetUnitByName(boi->second); const float radius = GetUnitDefRadius(ud, c.id); if (inCommand) { if (building) { if (f3Dist(build.pos, fac->pos) > fac->buildDistance + radius - 8.0f) { owner->moveType->StartMoving(build.pos, fac->buildDistance * 0.5f + radius); } else { StopMove(); // needed since above startmoving cancels this owner->moveType->KeepPointingTo(build.pos, (fac->buildDistance + radius) * 0.6f, false); } if (!fac->curBuild && !fac->terraforming) { building = false; StopMove(); //cancel the effect of KeepPointingTo FinishCommand(); } // This can only be true if two builders started building // the restricted unit in the same simulation frame else if (uh->unitsByDefs[owner->team][build.def->id].size() > build.def->maxThisUnit) { // unit restricted building = false; fac->StopBuild(); CancelRestrictedUnit(boi->second); } } else { build.Parse(c); if (uh->unitsByDefs[owner->team][build.def->id].size() >= build.def->maxThisUnit) { // unit restricted, don't bother moving all the way // to the construction site first before telling us // (since greyed-out icons can still be clicked etc, // would be better to prevent that but doesn't cover // case where limit reached while builder en-route) CancelRestrictedUnit(boi->second); StopMove(); } else { build.pos = helper->Pos2BuildPos(build); const float dist = f3Dist(build.pos, fac->pos); if ((dist < (fac->buildDistance * 0.6f + radius)) || (!owner->unitDef->canmove && (dist <= (fac->buildDistance + radius - 8.0f)))) { StopMove(); if (luaRules && !luaRules->AllowUnitCreation(build.def, owner, &build.pos)) { FinishCommand(); } else if (uh->maxUnits > (int) gs->Team(owner->team)->units.size()) { // max unitlimit reached buildRetries++; owner->moveType->KeepPointingTo(build.pos, fac->buildDistance * 0.7f + radius, false); if (fac->StartBuild(build) || (buildRetries > 20)) { building = true; } else { ENTER_MIXED; if ((owner->team == gu->myTeam) && !(buildRetries & 7)) { logOutput.Print("%s: Build pos blocked", owner->unitDef->humanName.c_str()); logOutput.SetLastMsgPos(owner->pos); } ENTER_SYNCED; helper->BuggerOff(build.pos, radius); NonMoving(); } } } else { if (owner->moveType->progressState == AMoveType::Failed) { if (++buildRetries > 5) { StopMove(); FinishCommand(); } } SetGoal(build.pos, owner->pos, fac->buildDistance * 0.4f + radius); } } } } else { //!inCommand BuildInfo bi; bi.pos.x=floor(c.params[0]/SQUARE_SIZE+0.5f)*SQUARE_SIZE; bi.pos.z=floor(c.params[2]/SQUARE_SIZE+0.5f)*SQUARE_SIZE; bi.pos.y=c.params[1]; CFeature* f=0; if (c.params.size()==4) bi.buildFacing = int(c.params[3]); bi.def = unitDefHandler->GetUnitByName(boi->second); uh->TestUnitBuildSquare(bi,f,owner->allyteam); if (f) { if (!owner->unitDef->canReclaim || !f->def->reclaimable) { // FIXME user shouldn't be able to queue buildings on top of features // in the first place (in this case). StopMove(); FinishCommand(); } else { Command c2; c2.id=CMD_RECLAIM; c2.options=0; c2.params.push_back(f->id+MAX_UNITS); commandQue.push_front(c2); SlowUpdate(); //this assumes that the reclaim command can never return directly without having reclaimed the target } } else { inCommand=true; SlowUpdate(); } } return; } switch (c.id) { case CMD_STOP: { ExecuteStop(c); return; } case CMD_REPAIR: { ExecuteRepair(c); return; } case CMD_CAPTURE: { ExecuteCapture(c); return; } case CMD_GUARD: { ExecuteGuard(c); return; } case CMD_RECLAIM: { ExecuteReclaim(c); return; } case CMD_RESURRECT: { ExecuteResurrect(c); return; } case CMD_PATROL: { ExecutePatrol(c); return; } case CMD_FIGHT: { ExecuteFight(c); return; } case CMD_RESTORE: { ExecuteRestore(c); return; } default: { CMobileCAI::SlowUpdate(); return; } } }
/** * @brief Executes the Fight command c */ void CMobileCAI::ExecuteFight(Command& c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); if (c.params.size() == 1 && !owner->weapons.empty()) { CWeapon* w = owner->weapons.front(); if ((orderTarget != NULL) && !w->AttackUnit(orderTarget, false)) { CUnit* newTarget = helper->GetClosestValidTarget(owner->pos, owner->maxRange, owner->allyteam, this); if ((newTarget != NULL) && w->AttackUnit(newTarget, false)) { c.params[0] = newTarget->id; inCommand = false; } else { w->AttackUnit(orderTarget, false); } } ExecuteAttack(c); return; } if (tempOrder) { inCommand = true; tempOrder = false; } if (c.params.size() < 3) { LOG_L(L_ERROR, "Received a Fight command with less than 3 params on %s in MobileCAI", owner->unitDef->humanName.c_str()); return; } if (c.params.size() >= 6) { if (!inCommand) { commandPos1 = c.GetPos(3); } } 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, owner->pos); if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) { commandPos1 = owner->pos; } } float3 pos = c.GetPos(0); if (!inCommand) { inCommand = true; commandPos2 = pos; lastUserGoal = commandPos2; } if (c.params.size() >= 6) { pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); } if (pos != goalPos) { SetGoal(pos, owner->pos); } if (owner->unitDef->canAttack && owner->fireState >= FIRESTATE_FIREATWILL && !owner->weapons.empty()) { const float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); const float searchRadius = owner->maxRange + 100 * owner->moveState * owner->moveState; CUnit* enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this); if (enemy != NULL) { PushOrUpdateReturnFight(); // make the attack-command inherit <c>'s options // NOTE: see AirCAI::ExecuteFight why we do not set INTERNAL_ORDER Command c2(CMD_ATTACK, c.options, enemy->id); commandQue.push_front(c2); inCommand = false; tempOrder = true; // avoid infinite loops (?) if (lastPC != gs->frameNum) { lastPC = gs->frameNum; SlowUpdate(); } return; } } if ((owner->pos - goalPos).SqLength2D() < (64 * 64) || (owner->moveType->progressState == AMoveType::Failed)){ FinishCommand(); } }
/** * @brief Executes the Fight command c */ void CMobileCAI::ExecuteFight(Command &c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); if(c.params.size() == 1) { if(orderTarget && !owner->weapons.empty() && !owner->weapons.front()->AttackUnit(orderTarget, false)) { CUnit* newTarget = helper->GetClosestValidTarget( owner->pos, owner->maxRange, owner->allyteam, this); if ((newTarget != NULL) && owner->weapons.front()->AttackUnit(newTarget, false)) { c.params[0] = newTarget->id; inCommand = false; } else { owner->weapons.front()->AttackUnit(orderTarget, false); } } ExecuteAttack(c); return; } if(tempOrder){ inCommand = true; tempOrder = false; } if (c.params.size() < 3) { 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, owner->pos); if ((owner->pos - commandPos1).SqLength2D() > (96 * 96)) { commandPos1 = owner->pos; } } float3 pos(c.params[0],c.params[1],c.params[2]); if(!inCommand){ inCommand = true; commandPos2 = pos; lastUserGoal = commandPos2; } if(c.params.size() >= 6){ pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); } if(pos!=goalPos){ SetGoal(pos, owner->pos); } if (owner->unitDef->canAttack && owner->fireState >= 2 && !owner->weapons.empty()) { const float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); const float searchRadius = owner->maxRange + 100 * owner->moveState * owner->moveState; CUnit* enemy = helper->GetClosestValidTarget(curPosOnLine, searchRadius, owner->allyteam, this); if (enemy != NULL) { Command c2; c2.id=CMD_FIGHT; 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((owner->pos - goalPos).SqLength2D() < (64 * 64) || (owner->moveType->progressState == AMoveType::Failed)){ FinishCommand(); } return; }
void CTransportCAI::ExecuteLoadUnits(Command& c) { CTransportUnit* transport = reinterpret_cast<CTransportUnit*>(owner); if (c.params.size() == 1) { // load single unit CUnit* unit = unitHandler->GetUnit(c.params[0]); if (!unit) { FinishCommand(); return; } if (c.options & INTERNAL_ORDER) { if (unit->commandAI->commandQue.empty()) { if (!LoadStillValid(unit)) { FinishCommand(); return; } } else { Command& currentUnitCommand = unit->commandAI->commandQue[0]; if ((currentUnitCommand.GetID() == CMD_LOAD_ONTO) && (currentUnitCommand.params.size() == 1) && (int(currentUnitCommand.params[0]) == owner->id)) { if ((unit->moveType->progressState == AMoveType::Failed) && (owner->moveType->progressState == AMoveType::Failed)) { unit->commandAI->FinishCommand(); FinishCommand(); return; } } else if (!LoadStillValid(unit)) { FinishCommand(); return; } } } if (inCommand) { if (!owner->script->IsBusy()) { FinishCommand(); } return; } if (unit && CanTransport(unit) && UpdateTargetLostTimer(int(c.params[0]))) { SetTransportee(unit); const float sqDist = unit->pos.SqDistance2D(owner->pos); const bool inLoadingRadius = (sqDist <= Square(owner->unitDef->loadingRadius)); CHoverAirMoveType* am = dynamic_cast<CHoverAirMoveType*>(owner->moveType); // subtracting 1 square to account for pathfinder/groundmovetype inaccuracy if (goalPos.SqDistance2D(unit->pos) > Square(owner->unitDef->loadingRadius - SQUARE_SIZE) || (!inLoadingRadius && (!owner->isMoving || (am && am->aircraftState != AAirMoveType::AIRCRAFT_FLYING)))) { SetGoal(unit->pos, owner->pos, std::min(64.0f, owner->unitDef->loadingRadius)); } if (inLoadingRadius) { if (am) { // handle air transports differently float3 wantedPos = unit->pos; wantedPos.y = static_cast<CTransportUnit*>(owner)->GetLoadUnloadHeight(wantedPos, unit); SetGoal(wantedPos, owner->pos); am->loadingUnits = true; am->ForceHeading(static_cast<CTransportUnit*>(owner)->GetLoadUnloadHeading(unit)); am->SetWantedAltitude(wantedPos.y - ground->GetHeightAboveWater(wantedPos.x, wantedPos.z)); am->maxDrift = 1; if ((owner->pos.SqDistance(wantedPos) < Square(AIRTRANSPORT_DOCKING_RADIUS)) && (abs(owner->heading-unit->heading) < AIRTRANSPORT_DOCKING_ANGLE) && (owner->updir.dot(UpVector) > 0.995f)) { am->loadingUnits = false; am->dontLand = true; owner->script->BeginTransport(unit); SetTransportee(NULL); transport->AttachUnit(unit, owner->script->QueryTransport(unit)); am->SetWantedAltitude(0); FinishCommand(); return; } } else { inCommand = true; StopMove(); owner->script->TransportPickup(unit); } } else if (owner->moveType->progressState == AMoveType::Failed && sqDist < (200 * 200)) { // if we're pretty close already but CGroundMoveType fails because it considers // the goal clogged (with the future passenger...), just try to move to the // point halfway between the transport and the passenger. SetGoal((unit->pos + owner->pos) * 0.5f, owner->pos); } } else { FinishCommand(); } } else if (c.params.size() == 4) { // area-load if (lastCall == gs->frameNum) { // avoid infinite loops return; } lastCall = gs->frameNum; const float3 pos = c.GetPos(0); const float radius = c.params[3]; CUnit* unit = FindUnitToTransport(pos, radius); if (unit && CanTransport(unit)) { Command c2(CMD_LOAD_UNITS, c.options|INTERNAL_ORDER, unit->id); commandQue.push_front(c2); inCommand = false; SlowUpdate(); return; } else { FinishCommand(); return; } } isFirstIteration = true; startingDropPos = float3(-1.0f, -1.0f, -1.0f); }
void CAirCAI::ExecuteFight(Command& c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); // FIXME: check owner->UsingScriptMoveType() and skip rest if true? AAirMoveType* myPlane = GetStrafeAirMoveType(owner); assert(owner == myPlane->owner); if (tempOrder) { tempOrder = false; inCommand = true; } if (c.params.size() < 3) { LOG_L(L_ERROR, "[ACAI::%s][f=%d][id=%d] CMD_FIGHT #params < 3", __FUNCTION__, gs->frameNum, owner->id); return; } if (c.params.size() >= 6) { if (!inCommand) { commandPos1 = c.GetPos(3); } } else { // HACK 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()<(127*127)){' // 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, owner->pos); if ((owner->pos - commandPos1).SqLength2D() > (150 * 150)) { commandPos1 = owner->pos; } } goalPos = c.GetPos(0); if (!inCommand) { inCommand = true; commandPos2 = goalPos; } if (c.params.size() >= 6) { goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); } // CMD_FIGHT is pretty useless if !canAttack, but we try to honour the modders wishes anyway... if (owner->unitDef->canAttack && (owner->fireState >= FIRESTATE_FIREATWILL) && (owner->moveState != MOVESTATE_HOLDPOS) && (owner->maxRange > 0)) { CUnit* enemy = NULL; if (owner->unitDef->IsFighterAirUnit()) { const float3 P = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed*10); const float R = 1000.0f * owner->moveState; enemy = CGameHelper::GetClosestEnemyAircraft(NULL, P, R, owner->allyteam); } if (IsValidTarget(enemy) && (owner->moveState != MOVESTATE_MANEUVER || LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000)) { // make the attack-command inherit <c>'s options // (if <c> is internal, then so are the attacks) // // this is needed because CWeapon code will not // fire on "internal" targets if the weapon has // noAutoTarget set (although the <enemy> CUnit* // is technically not a user-target, we treat it // as such) even when explicitly told to fight Command nc(CMD_ATTACK, c.options, enemy->id); commandQue.push_front(nc); tempOrder = true; inCommand = false; if (lastPC1 != gs->frameNum) { // avoid infinite loops lastPC1 = gs->frameNum; SlowUpdate(); } return; } else { const float3 P = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed * 20); const float R = 500.0f * owner->moveState; enemy = CGameHelper::GetClosestValidTarget(P, R, owner->allyteam, this); if (enemy != NULL) { PushOrUpdateReturnFight(); // make the attack-command inherit <c>'s options Command nc(CMD_ATTACK, c.options, enemy->id); commandQue.push_front(nc); tempOrder = true; inCommand = false; // avoid infinite loops (?) if (lastPC2 != gs->frameNum) { lastPC2 = gs->frameNum; SlowUpdate(); } return; } } } myPlane->goalPos = goalPos; const CStrafeAirMoveType* airMT = (!owner->UsingScriptMoveType())? static_cast<const CStrafeAirMoveType*>(myPlane): NULL; const float radius = (airMT != NULL)? std::max(airMT->turnRadius + 2*SQUARE_SIZE, 128.f) : 127.f; // we're either circling or will get to the target in 8 frames if ((owner->pos - goalPos).SqLength2D() < (radius * radius) || (owner->pos + owner->speed*8 - goalPos).SqLength2D() < 127*127) { FinishCommand(); } }
void CBuilderCAI::ExecuteReclaim(Command& c) { assert(owner->unitDef->canReclaim); if(c.params.size()==1){ int id=(int) c.params[0]; if (id >= MAX_UNITS) { //reclaim feature const CFeatureSet& fset = featureHandler->GetActiveFeatures(); CFeatureSet::const_iterator it = fset.find(id - MAX_UNITS); if (it != fset.end()) { CFeature* feature = *it; if(!ReclaimObject(feature)){ StopMove(); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); } else { AddUnitToFeatureReclaimers(owner); } } else { StopMove(); FinishCommand(); RemoveUnitFromFeatureReclaimers(owner); } RemoveUnitFromReclaimers(owner); } else { //reclaim unit CUnit* unit=uh->units[id]; if(unit && unit!=owner && unit->unitDef->reclaimable && UpdateTargetLostTimer(id) && unit->AllowedReclaim(owner) ){ if(!ReclaimObject(unit)){ StopMove(); FinishCommand(); } else { AddUnitToReclaimers(owner); } } else { RemoveUnitFromReclaimers(owner); FinishCommand(); } RemoveUnitFromFeatureReclaimers(owner); } } else if(c.params.size()==4){//area reclaim float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; const bool recAnyTeam = ((c.options & CONTROL_KEY) != 0); RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); if (FindReclaimableFeatureAndReclaim(pos, radius, c.options, true, recAnyTeam)) { inCommand=false; SlowUpdate(); return; } if(!(c.options & ALT_KEY)){ FinishCommand(); } } else { //wrong number of parameters RemoveUnitFromReclaimers(owner); RemoveUnitFromFeatureReclaimers(owner); FinishCommand(); } return; }
void CAirCAI::ExecuteFight(Command &c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); AAirMoveType* myPlane = (AAirMoveType*) owner->moveType; if(tempOrder){ tempOrder=false; inCommand=true; } if(c.params.size()<3){ //this shouldnt happen but anyway ... logOutput.Print("Error: got fight cmd with less than 3 params on %s in AirCAI", 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()<(127*127)){' // 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, owner->pos); if ((owner->pos - commandPos1).SqLength2D() > (150 * 150)) { commandPos1 = owner->pos; } } goalPos = float3(c.params[0], c.params[1], c.params[2]); if(!inCommand){ inCommand = true; commandPos2=goalPos; } if(c.params.size() >= 6){ goalPos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); } // CMD_FIGHT is pretty useless if !canAttack but we try to honour the modders wishes anyway... if (owner->unitDef->canAttack && owner->fireState >= 2 && owner->moveState != 0 && owner->maxRange > 0) { float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos + owner->speed*10); float testRad = 1000 * owner->moveState; CUnit* enemy = NULL; if(myPlane->IsFighter()) { enemy = helper->GetClosestEnemyAircraft(curPosOnLine, testRad, owner->allyteam); } if(IsValidTarget(enemy) && (owner->moveState!=1 || LinePointDist(commandPos1, commandPos2, enemy->pos) < 1000)) { Command nc; nc.id=CMD_ATTACK; nc.params.push_back(enemy->id); nc.options=c.options|INTERNAL_ORDER; commandQue.push_front(nc); tempOrder=true; inCommand=false; if(lastPC1!=gs->frameNum){ //avoid infinite loops lastPC1=gs->frameNum; SlowUpdate(); } return; } else { float3 curPosOnLine = ClosestPointOnLine( commandPos1, commandPos2, owner->pos + owner->speed * 20); float testRad = 500 * owner->moveState; enemy = helper->GetClosestEnemyUnit(curPosOnLine, testRad, owner->allyteam); if(IsValidTarget(enemy)) { Command nc; nc.id = CMD_ATTACK; nc.params.push_back(enemy->id); nc.options = c.options | INTERNAL_ORDER; PushOrUpdateReturnFight(); commandQue.push_front(nc); tempOrder = true; inCommand = false; if(lastPC2 != gs->frameNum){ //avoid infinite loops lastPC2 = gs->frameNum; SlowUpdate(); } return; } } } myPlane->goalPos = goalPos; if((owner->pos - goalPos).SqLength2D() < (127 * 127) || (owner->pos + owner->speed*8 - goalPos).SqLength2D() < (127 * 127)) { FinishCommand(); } return; }
void CBuilderCAI::ExecuteFight(Command& c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); CBuilder* fac=(CBuilder*)owner; if(tempOrder){ tempOrder=false; inCommand=true; } if(c.params.size()<3){ //this shouldnt happen but anyway ... logOutput.Print("Error: got fight cmd with less than 3 params on %s in BuilderCAI",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, owner->pos); if (f3SqLen(owner->pos - commandPos1) > (96 * 96)) { commandPos1 = owner->pos; } } float3 pos(c.params[0],c.params[1],c.params[2]); if (!inCommand) { inCommand = true; commandPos2 = pos; } if (c.params.size() >= 6) { pos = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); } if (pos!=goalPos) { SetGoal(pos, owner->pos); } float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); if ((owner->unitDef->canRepair || owner->unitDef->canAssist) && FindRepairTargetAndRepair(curPosOnLine, 300*owner->moveState+fac->buildDistance-8,c.options,true)){ tempOrder = true; inCommand = false; if (lastPC1 != gs->frameNum) { //avoid infinite loops lastPC1 = gs->frameNum; SlowUpdate(); } return; } if (owner->unitDef->canReclaim && FindReclaimableFeatureAndReclaim(curPosOnLine,300,c.options,false, false)) { tempOrder = true; inCommand = false; if (lastPC2 != gs->frameNum) { //avoid infinite loops lastPC2 = gs->frameNum; SlowUpdate(); } return; } if (f3SqLen(owner->pos - pos) < (64*64)) { FinishCommand(); return; } if(owner->haveTarget && owner->moveType->progressState!=AMoveType::Done){ StopMove(); } else if(owner->moveType->progressState!=AMoveType::Active){ owner->moveType->StartMoving(goalPos, 8); } return; }
void CCommandAI::GiveAllowedCommand(const Command& c, bool fromSynced) { if (ExecuteStateCommand(c)) { return; } switch (c.GetID()) { case CMD_SELFD: { if (owner->unitDef->canSelfD) { if (!(c.options & SHIFT_KEY) || commandQue.empty()) { if (owner->selfDCountdown != 0) { owner->selfDCountdown = 0; } else { owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1; } } else if (commandQue.back().GetID() == CMD_SELFD) { commandQue.pop_back(); } else { commandQue.push_back(c); } } return; } case CMD_SET_WANTED_MAX_SPEED: { if (CanSetMaxSpeed() && (commandQue.empty() || (commandQue.back().GetID() != CMD_SET_WANTED_MAX_SPEED))) { // bail early, do not check for overlaps or queue cancelling commandQue.push_back(c); if (commandQue.size()==1 && !owner->beingBuilt) { SlowUpdate(); } } return; } case CMD_WAIT: { GiveWaitCommand(c); return; } case CMD_INSERT: { ExecuteInsert(c, fromSynced); return; } case CMD_REMOVE: { ExecuteRemove(c); return; } } // flush the queue for immediate commands if (!(c.options & SHIFT_KEY)) { if (!commandQue.empty()) { const int& cmd_id = commandQue.front().GetID(); if ((cmd_id == CMD_MANUALFIRE) || (cmd_id == CMD_ATTACK) || (cmd_id == CMD_AREA_ATTACK)) { owner->AttackUnit(0,true); } waitCommandsAI.ClearUnitQueue(owner, commandQue); ClearCommandDependencies(); commandQue.clear(); } inCommand=false; SetOrderTarget(NULL); } AddCommandDependency(c); if (c.GetID() == CMD_PATROL) { CCommandQueue::iterator ci = commandQue.begin(); for (; ci != commandQue.end() && ci->GetID() != CMD_PATROL; ++ci) { // just increment } if (ci == commandQue.end()) { if (commandQue.empty()) { Command c2(CMD_PATROL, c.options); c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); commandQue.push_back(c2); } else { do { --ci; if (ci->params.size() >= 3) { Command c2(CMD_PATROL, c.options); c2.params = ci->params; commandQue.push_back(c2); break; } else if (ci == commandQue.begin()) { Command c2(CMD_PATROL, c.options); c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); commandQue.push_back(c2); break; } } while (ci != commandQue.begin()); } } } // cancel duplicated commands bool first; if (CancelCommands(c, commandQue, first) > 0) { if (first) { Command stopCommand(CMD_STOP); commandQue.push_front(stopCommand); SlowUpdate(); } return; } // do not allow overlapping commands if (!GetOverlapQueued(c).empty()) { return; } if (c.GetID() == CMD_ATTACK) { // avoid weaponless units moving to 0 distance when given attack order if (owner->weapons.empty() && (owner->unitDef->canKamikaze == false)) { Command c2(CMD_STOP); commandQue.push_back(c2); return; } } commandQue.push_back(c); if (commandQue.size() == 1 && !owner->beingBuilt && !owner->stunned) { SlowUpdate(); } }
void CTransportCAI::ExecuteLoadUnits(Command &c) { CTransportUnit* transport=(CTransportUnit*)owner; if(c.params.size()==1){ //load single unit if(transport->transportCapacityUsed >= owner->unitDef->transportCapacity){ FinishCommand(); return; } CUnit* unit=uh->units[(int)c.params[0]]; if (!unit) { FinishCommand(); return; } if(c.options & INTERNAL_ORDER) { if(unit->commandAI->commandQue.empty()){ if(!LoadStillValid(unit)){ FinishCommand(); return; } } else { Command & currentUnitCommand = unit->commandAI->commandQue[0]; if(currentUnitCommand.id == CMD_LOAD_ONTO && currentUnitCommand.params.size() == 1 && int(currentUnitCommand.params[0]) == owner->id){ if((unit->moveType->progressState == CMoveType::Failed) && (owner->moveType->progressState == CMoveType::Failed)){ unit->commandAI->FinishCommand(); FinishCommand(); return; } } else if(!LoadStillValid(unit)) { FinishCommand(); return; } } } if(inCommand){ if(!owner->cob->busy) FinishCommand(); return; } if(unit && CanTransport(unit) && UpdateTargetLostTimer(int(c.params[0]))){ toBeTransportedUnitId=unit->id; unit->toBeTransported=true; if(unit->mass+transport->transportMassUsed > owner->unitDef->transportMass){ FinishCommand(); return; } if(goalPos.distance2D(unit->pos)>10){ float3 fix = unit->pos; SetGoal(fix,owner->pos,64); } if(unit->pos.distance2D(owner->pos)<owner->unitDef->loadingRadius*0.9f){ if(CTAAirMoveType* am=dynamic_cast<CTAAirMoveType*>(owner->moveType)){ //handle air transports differently float3 wantedPos=unit->pos+UpVector*unit->model->height; SetGoal(wantedPos,owner->pos); am->dontCheckCol=true; am->ForceHeading(unit->heading); am->SetWantedAltitude(unit->model->height); am->maxDrift=1; //logOutput.Print("cai dist %f %f %f",owner->pos.distance(wantedPos),owner->pos.distance2D(wantedPos),owner->pos.y-wantedPos.y); if(owner->pos.distance(wantedPos)<4 && abs(owner->heading-unit->heading)<50 && owner->updir.dot(UpVector)>0.995f){ am->dontCheckCol=false; am->dontLand=true; std::vector<int> args; args.push_back((int)(unit->model->height*65536)); owner->cob->Call("BeginTransport",args); std::vector<int> args2; args2.push_back(0); args2.push_back((int)(unit->model->height*65536)); owner->cob->Call("QueryTransport",args2); ((CTransportUnit*)owner)->AttachUnit(unit,args2[0]); am->SetWantedAltitude(0); FinishCommand(); return; } } else { inCommand=true; scriptReady=false; StopMove(); std::vector<int> args; args.push_back(unit->id); owner->cob->Call("TransportPickup",args,ScriptCallback,this,0); } } } else { FinishCommand(); } } else if(c.params.size()==4){ //load in radius if(lastCall==gs->frameNum) //avoid infinite loops return; lastCall=gs->frameNum; float3 pos(c.params[0],c.params[1],c.params[2]); float radius=c.params[3]; CUnit* unit=FindUnitToTransport(pos,radius); if(unit && ((CTransportUnit*)owner)->transportCapacityUsed < owner->unitDef->transportCapacity){ Command c2; c2.id=CMD_LOAD_UNITS; c2.params.push_back(unit->id); c2.options=c.options | INTERNAL_ORDER; commandQue.push_front(c2); inCommand=false; SlowUpdate(); return; } else { FinishCommand(); return; } } return; }
void CBuilderCAI::ExecuteFight(Command& c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); if (tempOrder) { tempOrder = false; inCommand = true; } if (c.params.size() < 3) { // this shouldnt happen but anyway ... LOG_L(L_ERROR, "Received a Fight command with less than 3 params on %s in BuilderCAI", owner->unitDef->humanName.c_str()); return; } if (c.params.size() >= 6) { if (!inCommand) { commandPos1 = c.GetPos(3); } } 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, owner->pos); if (f3SqDist(owner->pos, commandPos1) > (96 * 96)) { commandPos1 = owner->pos; } } float3 pos = c.GetPos(0); if (!inCommand) { inCommand = true; commandPos2 = pos; } float3 curPosOnLine = ClosestPointOnLine(commandPos1, commandPos2, owner->pos); if (c.params.size() >= 6) { pos = curPosOnLine; } if (pos != goalPos) { SetGoal(pos, owner->pos); } const bool resurrectMode = !!(c.options & ALT_KEY); const bool reclaimEnemyMode = !!(c.options & META_KEY); const bool reclaimEnemyOnlyMode = (c.options & CONTROL_KEY) && (c.options & META_KEY); ReclaimOption recopt; if (resurrectMode) recopt |= REC_NONREZ; if (reclaimEnemyMode) recopt |= REC_ENEMY; if (reclaimEnemyOnlyMode) recopt |= REC_ENEMYONLY; const float searchRadius = (owner->immobile ? 0 : (300 * owner->moveState)) + ownerBuilder->buildDistance; if (!reclaimEnemyOnlyMode && (owner->unitDef->canRepair || owner->unitDef->canAssist) && // Priority 1: Repair FindRepairTargetAndRepair(curPosOnLine, searchRadius, c.options, true, resurrectMode)){ tempOrder = true; inCommand = false; if (lastPC1 != gs->frameNum) { //avoid infinite loops lastPC1 = gs->frameNum; SlowUpdate(); } return; } if (!reclaimEnemyOnlyMode && resurrectMode && owner->unitDef->canResurrect && // Priority 2: Resurrect (optional) FindResurrectableFeatureAndResurrect(curPosOnLine, searchRadius, c.options, false)) { tempOrder = true; inCommand = false; if (lastPC2 != gs->frameNum) { //avoid infinite loops lastPC2 = gs->frameNum; SlowUpdate(); } return; } if (owner->unitDef->canReclaim && // Priority 3: Reclaim / reclaim non resurrectable (optional) / reclaim enemy units (optional) FindReclaimTargetAndReclaim(curPosOnLine, searchRadius, c.options, recopt)) { tempOrder = true; inCommand = false; if (lastPC3 != gs->frameNum) { //avoid infinite loops lastPC3 = gs->frameNum; SlowUpdate(); } return; } if (f3SqDist(owner->pos, pos) < (64*64)) { FinishCommand(); return; } if (owner->haveTarget && owner->moveType->progressState != AMoveType::Done) { StopMove(); } else if (owner->moveType->progressState != AMoveType::Active) { owner->moveType->StartMoving(goalPos, 8); } }
void CWeapon::SlowUpdate() { SlowUpdate(false); }
void CBuilderCAI::ExecuteGuard(Command& c) { if (!owner->unitDef->canGuard) return; CUnit* guardee = unitHandler->GetUnit(c.params[0]); if (guardee == NULL) { FinishCommand(); return; } if (guardee == owner) { FinishCommand(); return; } if (UpdateTargetLostTimer(guardee->id) == 0) { FinishCommand(); return; } if (guardee->outOfMapTime > (GAME_SPEED * 5)) { FinishCommand(); return; } if (CBuilder* b = dynamic_cast<CBuilder*>(guardee)) { if (b->terraforming) { if (MoveInBuildRange(b->terraformCenter, b->terraformRadius * 0.7f)) { ownerBuilder->HelpTerraform(b); } else { StopSlowGuard(); } return; } else if (b->curReclaim && owner->unitDef->canReclaim) { StopSlowGuard(); if (!ReclaimObject(b->curReclaim)) { StopMove(); } return; } else if (b->curResurrect && owner->unitDef->canResurrect) { StopSlowGuard(); if (!ResurrectObject(b->curResurrect)) { StopMove(); } return; } else { ownerBuilder->StopBuild(); } const bool pushRepairCommand = ( b->curBuild != NULL) && ( b->curBuild->soloBuilder == NULL || b->curBuild->soloBuilder == owner) && (( b->curBuild->beingBuilt && owner->unitDef->canAssist) || ( !b->curBuild->beingBuilt && owner->unitDef->canRepair)); if (pushRepairCommand) { StopSlowGuard(); Command nc(CMD_REPAIR, c.options, b->curBuild->id); commandQue.push_front(nc); inCommand = false; SlowUpdate(); return; } } if (CFactory* fac = dynamic_cast<CFactory*>(guardee)) { const bool pushRepairCommand = ( fac->curBuild != NULL) && ( fac->curBuild->soloBuilder == NULL || fac->curBuild->soloBuilder == owner) && (( fac->curBuild->beingBuilt && owner->unitDef->canAssist) || (!fac->curBuild->beingBuilt && owner->unitDef->canRepair)); if (pushRepairCommand) { StopSlowGuard(); Command nc(CMD_REPAIR, c.options, fac->curBuild->id); commandQue.push_front(nc); inCommand = false; // SlowUpdate(); return; } } if (!(c.options & CONTROL_KEY) && IsUnitBeingReclaimed(guardee, owner)) return; const float3 pos = guardee->pos; const float radius = (guardee->immobile) ? guardee->radius : guardee->radius * 0.8f; // in case of mobile units reduce radius a bit if (MoveInBuildRange(pos, radius)) { StartSlowGuard(guardee->moveType->GetMaxSpeed()); const bool pushRepairCommand = ( guardee->health < guardee->maxHealth) && ( guardee->soloBuilder == NULL || guardee->soloBuilder == owner) && (( guardee->beingBuilt && owner->unitDef->canAssist) || (!guardee->beingBuilt && owner->unitDef->canRepair)); if (pushRepairCommand) { StopSlowGuard(); Command nc(CMD_REPAIR, c.options, guardee->id); commandQue.push_front(nc); inCommand = false; return; } else { NonMoving(); } } else { StopSlowGuard(); } }
void CCommandAI::GiveCommand(Command& c) { switch(c.id) { case CMD_FIRE_STATE: { if(c.params.empty()) return; owner->fireState=(int)c.params[0]; for(vector<CommandDescription>::iterator cdi=possibleCommands.begin();cdi!=possibleCommands.end();++cdi){ if(cdi->id==CMD_FIRE_STATE){ char t[10]; SNPRINTF(t, 10, "%d", (int)c.params[0]); cdi->params[0]=t; break; } } return; } case CMD_MOVE_STATE: { if(c.params.empty()) return; owner->moveState=(int)c.params[0]; for(vector<CommandDescription>::iterator cdi=possibleCommands.begin();cdi!=possibleCommands.end();++cdi){ if(cdi->id==CMD_MOVE_STATE){ char t[10]; SNPRINTF(t, 10, "%d", (int)c.params[0]); cdi->params[0]=t; break; } } return; } case CMD_REPEAT: { if(c.params.empty()) return; repeatOrders=!!c.params[0]; for(vector<CommandDescription>::iterator cdi=possibleCommands.begin();cdi!=possibleCommands.end();++cdi){ if(cdi->id==CMD_REPEAT){ char t[10]; SNPRINTF(t, 10, "%d", (int)c.params[0]); cdi->params[0]=t; break; } } return; } case CMD_TRAJECTORY: { if(c.params.empty() || owner->unitDef->highTrajectoryType<2) return; owner->useHighTrajectory=!!c.params[0]; for(vector<CommandDescription>::iterator cdi=possibleCommands.begin();cdi!=possibleCommands.end();++cdi){ if(cdi->id==CMD_TRAJECTORY){ char t[10]; SNPRINTF(t, 10, "%d", (int)c.params[0]); cdi->params[0]=t; break; } } return; } case CMD_ONOFF:{ if(c.params.empty() || !owner->unitDef->onoffable || owner->beingBuilt) return; if(c.params[0]==1){ owner->Activate(); } else if(c.params[0]==0) { owner->Deactivate(); } for(vector<CommandDescription>::iterator cdi=possibleCommands.begin();cdi!=possibleCommands.end();++cdi){ if(cdi->id==CMD_ONOFF){ char t[10]; SNPRINTF(t, 10, "%d", (int)c.params[0]); cdi->params[0]=t; break; } } return; } case CMD_CLOAK:{ if(c.params.empty() || !owner->unitDef->canCloak) return; if(c.params[0]==1){ owner->wantCloak=true; } else if(c.params[0]==0) { owner->wantCloak=false; owner->curCloakTimeout=gs->frameNum+owner->cloakTimeout; } for(vector<CommandDescription>::iterator cdi=possibleCommands.begin();cdi!=possibleCommands.end();++cdi){ if(cdi->id==CMD_CLOAK){ char t[10]; SNPRINTF(t, 10, "%d", (int)c.params[0]); cdi->params[0]=t; break; } } return; } case CMD_STOCKPILE:{ if(!stockpileWeapon) return; int change=1; if(c.options & RIGHT_MOUSE_KEY) change*=-1; if(c.options & CONTROL_KEY) change*=20; if(c.options & SHIFT_KEY) change*=5; stockpileWeapon->numStockpileQued+=change; if(stockpileWeapon->numStockpileQued<0) stockpileWeapon->numStockpileQued=0; UpdateStockpileIcon(); return; } case CMD_SELFD:{ if(owner->selfDCountdown){ owner->selfDCountdown=0; } else { owner->selfDCountdown = owner->unitDef->selfDCountdown*2+1; } return;} } if(!(c.options & SHIFT_KEY)){ if(!commandQue.empty()){ if(commandQue.front().id==CMD_ATTACK || commandQue.front().id==CMD_AREA_ATTACK || commandQue.front().id==CMD_DGUN) { owner->AttackUnit(0,true); } if((c.id==CMD_STOP || c.id==CMD_WAIT) && commandQue.front().id==CMD_WAIT) commandQue.pop_front(); else commandQue.clear(); } inCommand=false; if(orderTarget){ DeleteDeathDependence(orderTarget); orderTarget=0; } } if(c.id == CMD_PATROL){ std::deque<Command>::iterator ci = commandQue.begin(); for(; ci != commandQue.end() && ci->id!=CMD_PATROL; ci++); if(ci==commandQue.end()){ if(commandQue.empty()){ Command c2; c2.id = CMD_PATROL; c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); c2.options = c.options; commandQue.push_back(c2); } else { do{ ci--; if(ci->params.size() >=3){ Command c2; c2.id = CMD_PATROL; c2.params = ci->params; c2.options = c.options; commandQue.push_back(c2); ci=commandQue.begin(); } else if(ci==commandQue.begin()){ Command c2; c2.id = CMD_PATROL; c2.params.push_back(owner->pos.x); c2.params.push_back(owner->pos.y); c2.params.push_back(owner->pos.z); c2.options = c.options; commandQue.push_back(c2); } }while(ci!=commandQue.begin()); } } } std::deque<Command>::iterator ci = CCommandAI::GetCancelQueued(c); if(c.id<0 && ci != commandQue.end()){ do{ if(ci == commandQue.begin()){ commandQue.erase(ci); Command c2; c2.id = CMD_STOP; commandQue.push_front(c2); SlowUpdate(); } else { commandQue.erase(ci); } ci = CCommandAI::GetCancelQueued(c); }while(ci != commandQue.end()); return; } else if(ci != commandQue.end()){ if(ci == commandQue.begin()){ commandQue.erase(ci); Command c2; c2.id = CMD_STOP; commandQue.push_front(c2); SlowUpdate(); } else { commandQue.erase(ci); } ci = CCommandAI::GetCancelQueued(c); return; } if(!this->GetOverlapQueued(c).empty()){ return; } if(c.id==CMD_ATTACK && owner->weapons.empty() && owner->unitDef->canKamikaze==false){ //avoid weaponless units moving to 0 distance when given attack order Command c2; c2.id=CMD_STOP; commandQue.push_back(c2); return; } commandQue.push_back(c); if(commandQue.size()==1 && !owner->beingBuilt) SlowUpdate(); }
void CFactoryCAI::GiveCommandReal(const Command& c, bool fromSynced) { // move is always allowed for factories (passed to units it produces) if ((c.id == CMD_SET_WANTED_MAX_SPEED) || ((c.id != CMD_MOVE) && !AllowedCommand(c))) { return; } map<int, BuildOption>::iterator boi = buildOptions.find(c.id); // not a build order so queue it to built units if (boi == buildOptions.end()) { if ((nonQueingCommands.find(c.id) != nonQueingCommands.end()) || (c.id == CMD_INSERT) || (c.id == CMD_REMOVE) || (!(c.options & SHIFT_KEY) && ((c.id == CMD_WAIT) || (c.id == CMD_SELFD)))) { CCommandAI::GiveAllowedCommand(c); return; } if (!(c.options & SHIFT_KEY)) { waitCommandsAI.ClearUnitQueue(owner, newUnitCommands); newUnitCommands.clear(); } if (c.id != CMD_STOP) { if ((c.id == CMD_WAIT) || (c.id == CMD_SELFD)) { if (!newUnitCommands.empty() && (newUnitCommands.back().id == c.id)) { if (c.id == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_back(); } else { newUnitCommands.push_back(c); } } else { bool dummy; if (CancelCommands(c, newUnitCommands, dummy) > 0) { return; } else { if (GetOverlapQueued(c, newUnitCommands).empty()) { newUnitCommands.push_back(c); } else { return; } } } } // the first new-unit build order can not be WAIT or SELFD while (!newUnitCommands.empty()) { const int id = newUnitCommands.front().id; if ((id == CMD_WAIT) || (id == CMD_SELFD)) { if (c.id == CMD_WAIT) { waitCommandsAI.RemoveWaitCommand(owner, c); } newUnitCommands.pop_front(); } else { break; } } return; } BuildOption &bo = boi->second; int numItems = 1; if (c.options & SHIFT_KEY) { numItems *= 5; } if (c.options & CONTROL_KEY) { numItems *= 20; } if (c.options & RIGHT_MOUSE_KEY) { bo.numQued -= numItems; if (bo.numQued < 0) { bo.numQued = 0; } int numToErase = numItems; if (c.options & ALT_KEY) { for (unsigned int cmdNum = 0; cmdNum < commandQue.size() && numToErase; ++cmdNum) { if (commandQue[cmdNum].id == c.id) { commandQue[cmdNum].id = CMD_STOP; numToErase--; } } } else { for (int cmdNum = commandQue.size() - 1; cmdNum != -1 && numToErase; --cmdNum) { if (commandQue[cmdNum].id == c.id) { commandQue[cmdNum].id = CMD_STOP; numToErase--; } } } UpdateIconName(c.id,bo); SlowUpdate(); } else { if (c.options & ALT_KEY) { for (int a = 0; a < numItems; ++a) { if (repeatOrders) { Command nc(c); nc.options |= DONT_REPEAT; if (commandQue.empty()) { commandQue.push_front(nc); } else { commandQue.insert(commandQue.begin()+1, nc); } } else { commandQue.push_front(c); } } if (!repeatOrders) { building=false; CFactory* fac = (CFactory*)owner; fac->StopBuild(); } } else { for (int a = 0; a < numItems; ++a) { commandQue.push_back(c); } } bo.numQued += numItems; UpdateIconName(c.id, bo); SlowUpdate(); } }
void CGridManager::Update(int GameTime) { GameFrame=GameTime; if(GameFrame%UpdateModifierInterval==0){ SlowUpdate(); } }