Example #1
0
void CBuilderCAI::SlowUpdate()
{
	if(gs->paused) // Commands issued may invoke SlowUpdate when paused
		return;

	if (commandQue.empty()) {
		CMobileCAI::SlowUpdate();
		return;
	}

	if (owner->beingBuilt || owner->stunned) {
		return;
	}

	Command& c = commandQue.front();

	if (OutOfImmobileRange(c)) {
		FinishCommand();
		return;
	}

	switch (c.GetID()) {
		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: {
			if (c.GetID() < 0) {
				ExecuteBuildCmd(c);
			} else {
				CMobileCAI::SlowUpdate();
			}
			return;
		}
	}
}
void CBuilderCAI::SlowUpdate()
{
	if(commandQue.empty()){
		CMobileCAI::SlowUpdate();
		return;
	}

	Command& c=commandQue.front();
	CBuilder* fac=(CBuilder*)owner;
	float3 curPos=owner->pos;

	map<int,string>::iterator boi;
	if((boi=buildOptions.find(c.id))!=buildOptions.end()){
		const UnitDef* ud = unitDefHandler->GetUnitByName(boi->second);
		const float radius = GetUnitRadius(ud, c.id);
		if (inCommand) {
			if (building) {
				if (build.pos.distance2D(fac->pos) > fac->buildDistance+radius-8.0f) {
					owner->moveType->StartMoving(build.pos, fac->buildDistance*0.5f+radius);
				} else {
					StopMove();
					owner->moveType->KeepPointingTo(build.pos, (fac->buildDistance+radius)*0.6f, false);	//needed since above startmoving cancels this
				}
				if(!fac->curBuild && !fac->terraforming){
					building=false;
					StopMove();				//cancel the effect of KeepPointingTo
					FinishCommand();
				}
			} else {
				build.Parse(c);
				const float dist = build.pos.distance2D(fac->pos);
				if ((dist < (fac->buildDistance * 0.6f + radius)) ||
				    (!owner->unitDef->canmove && (dist <= (fac->buildDistance+radius-8.0f)))) {
					StopMove();
					if(uh->unitsType[owner->team][build.def->id]>=build.def->maxThisUnit){ //unit restricted
						ENTER_MIXED;
						if(owner->team == gu->myTeam){
							logOutput.Print("%s: Build failed, unit type limit reached",owner->unitDef->humanName.c_str());
							logOutput.SetLastMsgPos(owner->pos);
						}
						ENTER_SYNCED;
						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==CMoveType::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->destructable) {
					// 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;
		}
	}
}
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 (f3SqDist(build.pos, fac->pos) > Square(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 sqdist = f3SqDist(build.pos, fac->pos);

					if ((sqdist < Square(fac->buildDistance * 0.6f + radius)) ||
						(!owner->unitDef->canmove && (sqdist <= Square(fac->buildDistance + radius - 8.0f)))) {
						StopMove();

						if (luaRules && !luaRules->AllowUnitCreation(build.def, owner, &build.pos)) {
							FinishCommand();
						}
						else if (uh->maxUnits > (int) teamHandler->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;
		}
	}
}