void CBuilderCAI::ExecuteRepair(Command& c) { CBuilder* fac=(CBuilder*)owner; assert(owner->unitDef->canRepair || owner->unitDef->canAssist); if (c.params.size() == 1) { //repair unit CUnit* unit = uh->units[(int)c.params[0]]; if (tempOrder && owner->moveState == 1) { //limit how far away we go if (unit && LinePointDist(commandPos1, commandPos2, unit->pos) > 500) { StopMove(); FinishCommand(); return; } } if (unit && (unit->health < unit->maxHealth) && ((unit != owner) || owner->unitDef->canSelfRepair) && (!unit->soloBuilder || (unit->soloBuilder == owner)) && UpdateTargetLostTimer((int)c.params[0])) { if (f3SqDist(unit->pos, fac->pos) < Square(fac->buildDistance+unit->radius-8)) { StopMove(); fac->SetRepairTarget(unit); owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9f+unit->radius, false); } else { if (f3SqDist(goalPos, unit->pos) > 1) { SetGoal(unit->pos,owner->pos, fac->buildDistance*0.9f+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; }
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 ((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; } 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)){ CUnit* target=uh->units[(int)commandQue.front().params[0]]; 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)){ tempOrder=true; inCommand=false; if(lastPC2!=gs->frameNum){ //avoid infinite loops lastPC2=gs->frameNum; SlowUpdate(); } return; } if((owner->pos - pos).SqLength2D()<(64*64)){ FinishCommand(); return; } if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done){ StopMove(); } else if(owner->moveType->progressState!=CMoveType::Active){ owner->moveType->StartMoving(goalPos, 8); } return; }
void CBuilderCAI::ExecuteRepair(Command& c) { // not all builders are repair-capable by default if (!owner->unitDef->canRepair) return; CBuilder* builder = (CBuilder*) owner; if (c.params.size() == 1 || c.params.size() == 5) { // repair unit CUnit* unit = uh->GetUnit(c.params[0]); if (unit == NULL) { FinishCommand(); return; } if (tempOrder && owner->moveState == MOVESTATE_MANEUVER) { // limit how far away we go if (LinePointDist(commandPos1, commandPos2, unit->pos) > 500) { StopMove(); FinishCommand(); return; } } if (c.params.size() == 5) { const float3 pos(c.params[1], c.params[2], c.params[3]); 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())) || builder->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)) { builder->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]; builder->StopBuild(); if (FindRepairTargetAndRepair(pos, radius, c.options, false, (c.options & META_KEY))) { inCommand = false; SlowUpdate(); return; } if (!(c.options & ALT_KEY)) { FinishCommand(); } } else { FinishCommand(); } return; }
void CBuilderCAI::ExecuteFight(Command& c) { assert((c.options & INTERNAL_ORDER) || owner->unitDef->canFight); CBuilder* builder = (CBuilder*) owner; 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 = 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 (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)) + builder->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); } return; }
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->Load3DO(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(commandFromPatrol && owner->moveState==1){ //limit how far away we go if(unit && LinePointDist(commandPos1,commandPos2,unit->pos) > 500){ StopMove(); FinishCommand(); break; } } 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; commandPos1=curPos; 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 in BuilderCAI",owner->unitDef->humanName.c_str()); return; } patrolGoal=float3(c.params[0],c.params[1],c.params[2]); commandPos2=patrolGoal; if(!(patrolTime&3) && owner->fireState==2){ if(FindRepairTargetAndRepair(owner->pos,300*owner->moveState,c.options,true)){ CUnit* target=uh->units[(int)commandQue.front().params[0]]; if(owner->moveState!=1 || LinePointDist(commandPos1,commandPos2,target->pos) < 300){ commandFromPatrol=true; inCommand=false; SlowUpdate(); return; } else { commandQue.pop_front(); } } if(FindReclaimableFeatureAndReclaim(owner->pos,300*owner->moveState,c.options)){ commandFromPatrol=true; inCommand=false; SlowUpdate(); return; } } patrolTime++; if(!(patrolGoal==goalPos)){ SetGoal(patrolGoal,curPos); } if((curPos-patrolGoal).SqLength2D()<4096){ 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++; } commandPos1=commandPos2; } if(owner->haveTarget && owner->moveType->progressState!=CMoveType::Done) StopMove(); else if(owner->moveType->progressState!=CMoveType::Active) owner->moveType->StartMoving(goalPos, 8); 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(); }