void CBuilderCAI::ExecuteCapture(Command &c) { assert(owner->unitDef->canCapture); CBuilder* fac=(CBuilder*)owner; if(c.params.size()==1){ //capture unit CUnit* unit=uh->units[(int)c.params[0]]; if(unit && unit->team!=owner->team && UpdateTargetLostTimer((int)c.params[0])){ if(unit->pos.distance2D(fac->pos)<fac->buildDistance+unit->radius-8){ StopMove(); fac->SetCaptureTarget(unit); owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9f+unit->radius, false); } else { if(goalPos.distance2D(unit->pos)>1) SetGoal(unit->pos,owner->pos, fac->buildDistance*0.9f+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; }
void CBuilderCAI::ExecuteCapture(Command& c) { // not all builders are capture-capable by default if (!owner->unitDef->canCapture) return; CBuilder* builder = (CBuilder*) owner; if (c.params.size() == 1 || c.params.size() == 5) { // capture unit CUnit* unit = uh->GetUnit(c.params[0]); if (unit == NULL) { 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; // do not walk too far outside capture area if (((pos - unit->pos).SqLength2D() > (radius * radius) || (builder->curCapture == unit && unit->isMoving && !IsInBuildRange(unit)))) { StopMove(); FinishCommand(); return; } } if (unit->unitDef->capturable && unit->team != owner->team && UpdateTargetLostTimer(unit->id)) { if (MoveInBuildRange(unit)) { builder->SetCaptureTarget(unit); } } else { StopMove(); FinishCommand(); } } else if (c.params.size() == 4) { // area capture const float3 pos = c.GetPos(0); const float radius = c.params[3]; builder->StopBuild(); if (FindCaptureTargetAndCapture(pos, radius, c.options, (c.options & META_KEY))) { inCommand = false; SlowUpdate(); return; } if (!(c.options & ALT_KEY)) { FinishCommand(); } } else { FinishCommand(); } 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(); }