Example #1
0
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;
}
Example #2
0
bool CBuilderCAI::ReclaimObject(CSolidObject* object) {
	if (MoveInBuildRange(object)) {
		ownerBuilder->SetReclaimTarget(object);
	} else {
		if (owner->moveType->progressState == AMoveType::Failed) {
			return false;
		}
	}

	return true;
}
Example #3
0
bool CBuilderCAI::ResurrectObject(CFeature *feature) {
	if (MoveInBuildRange(feature, true)) {
		ownerBuilder->SetResurrectTarget(feature);
	} else {
		if (owner->moveType->progressState == AMoveType::Failed) {
			return false;
		}
	}

	return true;
}
Example #4
0
void CBuilderCAI::ExecuteRestore(Command& c)
{
	if (!owner->unitDef->canRestore)
		return;

	if (inCommand) {
		if (!ownerBuilder->terraforming) {
			FinishCommand();
		}
	} else if (owner->unitDef->canRestore) {
		const float3 pos(c.params[0], CGround::GetHeightReal(c.params[0], c.params[2]), c.params[2]);
		const float radius = std::min(c.params[3], 200.0f);

		if (MoveInBuildRange(pos, radius * 0.7f)) {
			ownerBuilder->StartRestore(pos, radius);
			inCommand = true;
		}
	}
}
Example #5
0
void CBuilderCAI::ExecuteGuard(Command& c)
{
	if (!owner->unitDef->canGuard)
		return;

	CBuilder* builder = (CBuilder*) owner;
	CUnit* guardee = uh->GetUnit(c.params[0]);

	if (guardee == NULL) { FinishCommand(); return; }
	if (guardee == owner) { FinishCommand(); return; }
	if (UpdateTargetLostTimer(guardee->id) == 0) { FinishCommand(); return; }
	if (guardee->outOfMapTime > (GAME_SPEED * 5)) { FinishCommand(); return; }


	if (CBuilder* b = dynamic_cast<CBuilder*>(guardee)) {
		if (b->terraforming) {
			if (MoveInBuildRange(b->terraformCenter, b->terraformRadius * 0.7f)) {
				builder->HelpTerraform(b);
			} else {
				StopSlowGuard();
			}
			return;
		} else if (b->curReclaim && owner->unitDef->canReclaim) {
			StopSlowGuard();
			if (!ReclaimObject(b->curReclaim)) {
				StopMove();
			}
			return;
		} else if (b->curResurrect && owner->unitDef->canResurrect) {
			StopSlowGuard();
			if (!ResurrectObject(b->curResurrect)) {
				StopMove();
			}
			return;
		} else {
			builder->StopBuild();
		}

		const bool pushRepairCommand =
			(  b->curBuild != NULL) &&
			(  b->curBuild->soloBuilder == NULL || b->curBuild->soloBuilder == owner) &&
			(( b->curBuild->beingBuilt && owner->unitDef->canAssist) ||
			( !b->curBuild->beingBuilt && owner->unitDef->canRepair));

		if (pushRepairCommand) {
			StopSlowGuard();

			Command nc(CMD_REPAIR, c.options);
			nc.params.push_back(b->curBuild->id);

			commandQue.push_front(nc);
			inCommand = false;
			SlowUpdate();
			return;
		}
	}

	if (CFactory* fac = dynamic_cast<CFactory*>(guardee)) {
		const bool pushRepairCommand =
			(  fac->curBuild != NULL) &&
			(  fac->curBuild->soloBuilder == NULL || fac->curBuild->soloBuilder == owner) &&
			(( fac->curBuild->beingBuilt && owner->unitDef->canAssist) ||
			 (!fac->curBuild->beingBuilt && owner->unitDef->canRepair));

		if (pushRepairCommand) {
			StopSlowGuard();

			Command nc(CMD_REPAIR, c.options);
			nc.params.push_back(fac->curBuild->id);

			commandQue.push_front(nc);
			inCommand = false;
			// SlowUpdate();
			return;
		}
	}

	if (!(c.options & CONTROL_KEY) && IsUnitBeingReclaimed(guardee, owner))
		return;

	const float3 pos    = guardee->pos;
	const float  radius = (guardee->immobile) ? guardee->radius : guardee->radius * 0.8f; // in case of mobile units reduce radius a bit
	
	if (MoveInBuildRange(pos, radius)) {
		StartSlowGuard(guardee->moveType->GetMaxSpeed());

		const bool pushRepairCommand =
			(  guardee->health < guardee->maxHealth) &&
			(  guardee->soloBuilder == NULL || guardee->soloBuilder == owner) &&
			(( guardee->beingBuilt && owner->unitDef->canAssist) ||
			 (!guardee->beingBuilt && owner->unitDef->canRepair));

		if (pushRepairCommand) {
			StopSlowGuard();

			Command nc(CMD_REPAIR, c.options);
			nc.params.push_back(guardee->id);

			commandQue.push_front(nc);
			inCommand = false;
			return;
		} else {
			NonMoving();
		}
	} else {
		StopSlowGuard();
	}
}
Example #6
0
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;
}
Example #7
0
void CBuilderCAI::ExecuteBuildCmd(Command& c)
{
	CBuilder* builder = (CBuilder*) owner;

	map<int, string>::iterator boi = buildOptions.find(c.GetID());
	if (boi == buildOptions.end())
		return;

	if (!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];

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

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

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

		if (f != NULL) {
			if (!bi.def->isFeature || bi.def->wreckName != f->def->name) {
				ReclaimFeature(f);
			} else {
				FinishCommand();
			}
		} else {
			inCommand = true;
			build.Parse(c);
			ExecuteBuildCmd(c);
		}
		return;
	}

	assert(build.def);
	const float radius = GetBuildOptionRadius(build.def, c.GetID());
	if (building) {
		MoveInBuildRange(build.pos, radius);

		if (!builder->curBuild && !builder->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;
			builder->StopBuild();
			CancelRestrictedUnit(boi->second);
		}
	} else {
		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();
			return;
		}

		build.pos = helper->Pos2BuildPos(build, true);

		// 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)
		const bool checkBuildPos = (gs->frameNum % (5 * UNIT_SLOWUPDATE_RATE)) < UNIT_SLOWUPDATE_RATE; //FIXME add a per-unit solution to better balance the load?
		CFeature* feature = NULL;
		if (checkBuildPos && !uh->TestUnitBuildSquare(build, feature, owner->allyteam, true)) {
			if (!feature) {
				const int yardxpos = int(build.pos.x + 4) / SQUARE_SIZE;
				const int yardypos = int(build.pos.z + 4) / SQUARE_SIZE;
				const CSolidObject* s = groundBlockingObjectMap->GroundBlocked(yardxpos, yardypos);
				const CUnit* u = dynamic_cast<const CUnit*>(s);
				if (u != NULL) {
					const bool canAssist =
						   u->beingBuilt
						&& owner->unitDef->canAssist
						&& (!u->soloBuilder || (u->soloBuilder == owner));

					if ((u->unitDef != build.def) || !canAssist) {
						StopMove();
						FinishCommand();
						return;
					}
				}
			}
		}

		if (MoveInBuildRange(build.pos, radius, true)) {
			if (luaRules && !luaRules->AllowUnitCreation(build.def, owner, &build)) {
				StopMove(); // cancel KeepPointingTo
				FinishCommand();
			}
			else if (!teamHandler->Team(owner->team)->AtUnitLimit()) {
				// unit-limit not yet reached
				CFeature* f = NULL;

				bool waitstance = false;
				if (builder->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
					helper->BuggerOff(build.pos, std::max(radius, fpRadius), false, true, owner->team, NULL);
					NonMoving();
				}
			}
		} else {
			if (owner->moveType->progressState == AMoveType::Failed) {
				if (++buildRetries > 5) {
					StopMove();
					FinishCommand();
				}
			}
		}
	}
}
Example #8
0
inline bool CBuilderCAI::MoveInBuildRange(const CWorldObject* obj, const bool checkMoveTypeForFailed)
{
	return MoveInBuildRange(obj->pos, obj->radius);
}
Example #9
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;
				}
			}
		}
	}
}