buildercai.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 1,458 行 · 第 1/3 页

CPP
1,458
字号
{
	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 (f3Dist(unit->pos, fac->pos) < fac->buildDistance+unit->radius-8) {
				StopMove();
				fac->SetRepairTarget(unit);
				owner->moveType->KeepPointingTo(unit->pos, fac->buildDistance*0.9f+unit->radius, false);
			} else {
				if (f3Dist(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::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 (f3Dist(unit->pos, 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 (f3Dist(goalPos, 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::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 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();
				}
			} else {
				StopMove();
				FinishCommand();
			}
			RemoveUnitFromReclaimers(owner);

		} else {                   //reclaim unit
			CUnit* unit=uh->units[id];
			if(unit && unit!=owner && unit->unitDef->reclaimable && UpdateTargetLostTimer(id)){
				if(!ReclaimObject(unit)){
					StopMove();
					FinishCommand();
				} else {
					AddUnitToReclaimers(owner);
				}
			} else {
				RemoveUnitFromReclaimers(owner);
				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];
		const bool recAnyTeam = ((c.options & CONTROL_KEY) != 0);
		RemoveUnitFromReclaimers(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);
		FinishCommand();
	}
	return;
}


void CBuilderCAI::ExecuteResurrect(Command& c)
{
	assert(owner->unitDef->canResurrect);
	CBuilder* fac=(CBuilder*)owner;
	if(c.params.size()==1){
		int id=(int)c.params[0];
		if(id>=MAX_UNITS){		//resurrect feature
			CFeatureSet::const_iterator it = featureHandler->GetActiveFeatures().find(id - MAX_UNITS);
			if (it != featureHandler->GetActiveFeatures().end() && (*it)->createdFromUnit != "") {
				CFeature* feature = *it;
				if (f3Dist(feature->pos, fac->pos) < fac->buildDistance*0.9f+feature->radius) {
					StopMove();
					owner->moveType->KeepPointingTo(feature->pos, fac->buildDistance*0.9f+feature->radius, false);
					fac->SetResurrectTarget(feature);
				} else {
					if (f3Dist(goalPos, feature->pos) > 1) {
						SetGoal(feature->pos,owner->pos, fac->buildDistance*0.8f+feature->radius);
					} else {
						if(owner->moveType->progressState==CMoveType::Failed){
							StopMove();
							FinishCommand();
						}
					}
				}
			} else {
				if(fac->lastResurrected && uh->units[fac->lastResurrected] && owner->unitDef->canRepair){	//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;
}


void CBuilderCAI::ExecutePatrol(Command& c)
{
	assert(owner->unitDef->canPatrol);
	if(c.params.size()<3){		//this shouldnt happen but anyway ...
		logOutput.Print("Error: got patrol cmd with less than 3 params on %s in buildercai",
			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;
}


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!=CMoveType::Done){
		StopMove();
	} else if(owner->moveType->progressState!=CMoveType::Active){
		owner->moveType->StartMoving(goalPos, 8);
	}
	return;
}


void CBuilderCAI::ExecuteRestore(Command& c)
{
	assert(owner->unitDef->canRestore);
	CBuilder* fac=(CBuilder*)owner;
	if(inCommand){
		if(!fac->terraforming){
			FinishCommand();
		}
	} else if(owner->unitDef->canRestore){
		float3 pos(c.params[0],c.params[1],c.params[2]);
		pos.y = ground->GetHeight2(pos.x,pos.y);
		float radius(c.params[3]);
		if (radius>200) radius = 200;
		if (f3Dist(fac->pos, pos) < fac->buildDistance-1) {
			StopMove();
			fac->StartRestore(pos,radius);
			owner->moveType->KeepPointingTo(pos, fac->buildDistance*0.9f, false);
			inCommand=true;
		} else {
			SetGoal(pos,owner->pos, fac->buildDistance*0.9f);
		}
	}
	return;
}


int CBuilderCAI::GetDefaultCmd(CUnit* pointed, CFeature* feature)
{
	if (pointed) {
		if (!gs->Ally(gu->myAllyTeam, pointed->allyteam)) {
			if (owner->unitDef->canAttack && (owner->maxRange > 0)) {
				return CMD_ATTACK;
			} else if (owner->unitDef->canReclaim && pointed->unitDef->reclaimable) {
				return CMD_RECLAIM;
			}
		} else {
			CTransportCAI* tran = dynamic_cast<CTransportCAI*>(pointed->commandAI);
			if ((pointed->health < pointed->maxHealth) &&
			    (!pointed->soloBuilder || (pointed->soloBuilder == owner)) &&
			    (( pointed->beingBuilt && owner->unitDef->canAssist) ||
			     (!pointed->beingBuilt && owner->unitDef->canRepair))) {
				return CMD_REPAIR;
			} else if (tran && tran->CanTransport(owner)) {
				return CMD_LOAD_ONTO;
			} else if (owner->unitDef->canGuard) {
				return CMD_GUARD;
			}
		}
	}
	if (feature) {
		if (owner->unitDef->canResurrect && !feature->createdFromUnit.empty()) {
			return CMD_RESURRECT;
		} else if(owner->unitDef->canReclaim && feature->def->reclaimable) {
			return CMD_RECLAIM;
		}
	}
	return CMD_MOVE;
}


void CBuilderCAI::AddUnitToReclaimers(CUnit* unit)
{
	reclaimers.insert(unit);
}


void CBuilderCAI::RemoveUnitFromReclaimers(CUnit* unit)
{
	reclaimers.erase(unit);
}


/** check if a unit is being reclaimed by a friendly con.

we assume that there won't be a lot of reclaimers because performance would suck
if there were. ideally reclaimers should be assigned on a per-unit basis, but
this requires tracking of deaths, which albeit already done isn't exactly simple
to follow.

TODO easy: store reclaiming units per allyteam
TODO harder: update reclaimers as they start/finish reclaims and/or die */
bool CBuilderCAI::IsUnitBeingReclaimedByFriend(CUnit* unit)
{
	bool retval = false;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?