示例#1
0
void CBuilderCAI::GiveCommandReal(const Command& c, bool fromSynced)
{
	if (!AllowedCommand(c, fromSynced))
		return;

	// don't guard yourself
	if ((c.GetID() == CMD_GUARD) &&
	    (c.params.size() == 1) && ((int)c.params[0] == owner->id)) {
		return;
	}

	// stop building/reclaiming/... if the new command is not queued, i.e. replaces our current activity
	// FIXME should happen just before CMobileCAI::GiveCommandReal? (the new cmd can still be skipped!)
	if ((c.GetID() != CMD_WAIT && c.GetID() != CMD_SET_WANTED_MAX_SPEED) && !(c.options & SHIFT_KEY)) {
		if (nonQueingCommands.find(c.GetID()) == nonQueingCommands.end()) {
			building = false;
			static_cast<CBuilder*>(owner)->StopBuild();
		}
	}

	if (buildOptions.find(c.GetID()) != buildOptions.end()) {
		if (c.params.size() < 3)
			return;

		BuildInfo bi;
		bi.pos = c.GetPos(0);

		if (c.params.size() == 4)
			bi.buildFacing = abs((int)c.params[3]) % NUM_FACINGS;

		bi.def = unitDefHandler->GetUnitDefByID(-c.GetID());
		bi.pos = CGameHelper::Pos2BuildPos(bi, true);

		// We are a static building, check if the buildcmd is in range
		if (!owner->unitDef->canmove) {
			if (!IsInBuildRange(bi.pos, GetBuildOptionRadius(bi.def, c.GetID()))) {
				return;
			}
		}

		const CUnit* nanoFrame = NULL;

		// check if the buildpos is blocked
		if (IsBuildPosBlocked(bi, &nanoFrame))
			return;

		// if it is a nanoframe help to finish it
		if (nanoFrame != NULL) {
			Command c2(CMD_REPAIR, c.options | INTERNAL_ORDER, nanoFrame->id);
			CMobileCAI::GiveCommandReal(c2, fromSynced);
			CMobileCAI::GiveCommandReal(c, fromSynced);
			return;
		}
	} else {
		if (c.GetID() < 0)
			return;
	}

	CMobileCAI::GiveCommandReal(c, fromSynced);
}
示例#2
0
void CBuilderCAI::ExecuteBuildCmd(Command& c)
{
	const map<int, string>::const_iterator boi = buildOptions.find(c.GetID());

	if (boi == buildOptions.end())
		return;

	if (!inCommand) {
		BuildInfo bi;
		bi.pos.x = math::floor(c.params[0] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE;
		bi.pos.z = math::floor(c.params[2] / SQUARE_SIZE + 0.5f) * SQUARE_SIZE;
		bi.pos.y = c.params[1];

		if (c.params.size() == 4)
			bi.buildFacing = abs((int)c.params[3]) % NUM_FACINGS;

		bi.def = unitDefHandler->GetUnitDefByName(boi->second);

		CFeature* f = NULL;
		CGameHelper::TestUnitBuildSquare(bi, f, owner->allyteam, true);

		if (f != NULL) {
			if (!bi.def->isFeature || bi.def->wreckName != f->def->name) {
				ReclaimFeature(f);
			} else {
				FinishCommand();
			}
			return;
		}

		inCommand = true;
		build.Parse(c);
	}

	assert(build.def->id == -c.GetID() && build.def->id != 0);
	const float buildeeRadius = GetBuildOptionRadius(build.def, c.GetID());

	if (building) {
		// keep moving until 3D distance to buildPos is LEQ our buildDistance
		MoveInBuildRange(build.pos, 0.0f);

		if (!ownerBuilder->curBuild && !ownerBuilder->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 (unitHandler->unitsByDefs[owner->team][build.def->id].size() > build.def->maxThisUnit) {
			// unit restricted
			building = false;
			ownerBuilder->StopBuild();
			CancelRestrictedUnit(boi->second);
		}
	} else {
		if (unitHandler->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();
			return;
		}

		build.pos = CGameHelper::Pos2BuildPos(build, true);

		// keep moving until until 3D distance to buildPos is LEQ our buildDistance
		if (MoveInBuildRange(build.pos, 0.0f, true)) {
			if (IsBuildPosBlocked(build)) {
				StopMove();
				FinishCommand();
				return;
			}

			if (!eventHandler.AllowUnitCreation(build.def, owner, &build)) {
				StopMove(); // cancel KeepPointingTo
				FinishCommand();
				return;
			}

			if (teamHandler->Team(owner->team)->AtUnitLimit()) {
				return;
			}

			CFeature* f = NULL;

			bool waitstance = false;
			if (ownerBuilder->StartBuild(build, f, waitstance) || (++buildRetries > 30)) {
				building = true;
			}
			else if (f != NULL && (!build.def->isFeature || build.def->wreckName != f->def->name)) {
				inCommand = false;
				ReclaimFeature(f);
			}
			else if (!waitstance) {
				const float fpSqRadius = (build.def->xsize * build.def->xsize + build.def->zsize * build.def->zsize);
				const float fpRadius = (math::sqrt(fpSqRadius) * 0.5f) * SQUARE_SIZE;

				// tell everything within the radius of the soon-to-be buildee
				// to get out of the way; using the model radius is not correct
				// because this can be shorter than half the footprint diagonal
				CGameHelper::BuggerOff(build.pos, std::max(buildeeRadius, fpRadius), false, true, owner->team, NULL);
				NonMoving();
			}
		} else {
			if (owner->moveType->progressState == AMoveType::Failed) {
				if (++buildRetries > 5) {
					StopMove();
					FinishCommand();
					return;
				}
			}

			// we are on the way to the buildpos, meanwhile it can happen
			// that another builder already finished our buildcmd or blocked
			// the buildpos with another building (skip our buildcmd then)
			if ((++randomCounter % 5) == 0) {
				if (IsBuildPosBlocked(build)) {
					StopMove();
					FinishCommand();
					return;
				}
			}
		}
	}
}