Exemple #1
0
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced)
{
	// TODO check if the command is in the map first, for more commands
	switch (c.GetID()) {
		case CMD_MOVE:
		case CMD_ATTACK:
		case CMD_AREA_ATTACK:
		case CMD_RECLAIM:
		case CMD_REPAIR:
		case CMD_RESURRECT:
		case CMD_PATROL:
		case CMD_RESTORE:
		case CMD_FIGHT:
		case CMD_MANUALFIRE:
		case CMD_UNLOAD_UNIT:
		case CMD_UNLOAD_UNITS: {
			if (!IsCommandInMap(c)) { return false; }
		} break;

		default: {
			// build commands
			if (c.GetID() < 0 && !IsCommandInMap(c)) { return false; }
		} break;
	}


	const UnitDef* ud = owner->unitDef;
	// AI's may do as they like
	const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team);
	const bool aiOrder = (!saids.empty());
	const int& cmd_id = c.GetID();
	
	switch (cmd_id) {
		case CMD_MANUALFIRE:
			if (!ud->canManualFire)
				return false;

		case CMD_ATTACK: {
			if (!IsAttackCapable())
				return false;

			if (c.params.size() == 1) {
				const CUnit* attackee = GetCommandUnit(c, 0);

				if (attackee && !attackee->pos.IsInBounds()) {
					return false;
				}
			} else {
				if (c.params.size() == 3) {
					const float3 cPos(c.params[0], c.params[1], c.params[2]);

					// check if attack ground is really attack ground
					if (!aiOrder && !fromSynced &&
						fabs(cPos.y - ground->GetHeightReal(cPos.x, cPos.z)) > SQUARE_SIZE) {
						return false;
					}
				}
			}
			break;
		}

		case CMD_MOVE:      if (!ud->canmove)       return false; break;
		case CMD_FIGHT:     if (!ud->canFight)      return false; break;
		case CMD_GUARD: {
			const CUnit* guardee = GetCommandUnit(c, 0);

			if (!ud->canGuard) { return false; }
			if (owner && !owner->pos.IsInBounds()) { return false; }
			if (guardee && !guardee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_PATROL: {
			if (!ud->canPatrol) { return false; }
		} break;

		case CMD_CAPTURE: {
			const CUnit* capturee = GetCommandUnit(c, 0);

			if (!ud->canCapture) { return false; }
			if (capturee && !capturee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_RECLAIM: {
			const CUnit* reclaimeeUnit = GetCommandUnit(c, 0);
			const CFeature* reclaimeeFeature = NULL;

			if (c.IsAreaCommand()) { return true; }
			if (!ud->canReclaim) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; }

			if (reclaimeeUnit == NULL && !c.params.empty()) {
				const unsigned int reclaimeeFeatureID(c.params[0]);

				if (reclaimeeFeatureID >= uh->MaxUnits()) {
					reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - uh->MaxUnits());

					if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) {
						return false;
					}
				}
			}
		} break;

		case CMD_RESTORE: {
			if (!ud->canRestore || mapDamage->disabled) {
				return false;
			}
		} break;

		case CMD_RESURRECT: {
			if (!ud->canResurrect) { return false; }
		} break;

		case CMD_REPAIR: {
			const CUnit* repairee = GetCommandUnit(c, 0);

			if (!ud->canRepair && !ud->canAssist) { return false; }
			if (repairee && !repairee->pos.IsInBounds()) { return false; }
			if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; }
		} break;
	}


	if (cmd_id == CMD_FIRE_STATE
			&& (c.params.empty() || !CanChangeFireState()))
	{
		return false;
	}
	if (cmd_id == CMD_MOVE_STATE
			&& (c.params.empty() || (!ud->canmove && !ud->builder)))
	{
		return false;
	}
	if (cmd_id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_TRAJECTORY
			&& (c.params.empty() || ud->highTrajectoryType < 2))
	{
		return false;
	}
	if (cmd_id == CMD_ONOFF
			&& (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_STOCKPILE && !stockpileWeapon)
	{
		return false;
	}
	return true;
}
Exemple #2
0
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced)
{
	// TODO check if the command is in the map first, for more commands
	switch (c.GetID()) {
		case CMD_MOVE:
		case CMD_ATTACK:
		case CMD_AREA_ATTACK:
		case CMD_RECLAIM:
		case CMD_REPAIR:
		case CMD_RESURRECT:
		case CMD_PATROL:
		case CMD_RESTORE:
		case CMD_FIGHT:
		case CMD_MANUALFIRE:
		case CMD_UNLOAD_UNIT:
		case CMD_UNLOAD_UNITS: {
			if (!IsCommandInMap(c)) { return false; }
		} break;

		default: {
			// build commands
			if (c.GetID() < 0 && !IsCommandInMap(c)) { return false; }
		} break;
	}


	const UnitDef* ud = owner->unitDef;
	// AI's may do as they like
	const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team);
	const bool aiOrder = (!saids.empty());
	const int& cmd_id = c.GetID();
	
	switch (cmd_id) {
		case CMD_MANUALFIRE:
			if (!ud->canManualFire)
				return false;

		case CMD_ATTACK: {
			if (!IsAttackCapable())
				return false;

			if (c.params.size() == 1) {
				const CUnit* attackee = GetCommandUnit(c, 0);

				if (attackee == NULL)
					return false;
				if (!attackee->pos.IsInBounds())
					return false;
			} else {
				if (c.params.size() >= 3) {
					const float3 cPos(c.params[0], c.params[1], c.params[2]);
					//FIXME is fromSynced really sync-safe??? const float gHeight = ground->GetHeightReal(cPos.x, cPos.z, fromSynced);
					const float gHeight = ground->GetHeightReal(cPos.x, cPos.z, true);

					#if 0
					// check if attack-ground is really attack-ground
					//
					// NOTE:
					//     problematic if command contains value from UHM
					//     but is evaluated in synced context against SHM
					//     after roundtrip (when UHM and SHM differ a lot)
					//
					//     instead just clamp the elevation, which creates
					//     fewer issues overall (eg. artillery force-firing
					//     at positions outside LOS where UHM and SHM do not
					//     match will not be broken)
					//
					
					if (!aiOrder && math::fabs(cPos.y - gHeight) > SQUARE_SIZE) {
						return false;
					}
					#else
					if (!aiOrder) {
						Command& cc = const_cast<Command&>(c);
						cc.params[1] = gHeight;
					}

					return true;
					#endif
				}
			}
			break;
		}

		case CMD_MOVE:      if (!ud->canmove)       return false; break;
		case CMD_FIGHT:     if (!ud->canFight)      return false; break;
		case CMD_GUARD: {
			const CUnit* guardee = GetCommandUnit(c, 0);

			if (!ud->canGuard) { return false; }
			if (owner && !owner->pos.IsInBounds()) { return false; }
			if (guardee && !guardee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_PATROL: {
			if (!ud->canPatrol) { return false; }
		} break;

		case CMD_CAPTURE: {
			const CUnit* capturee = GetCommandUnit(c, 0);

			if (!ud->canCapture) { return false; }
			if (capturee && !capturee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_RECLAIM: {
			const CUnit* reclaimeeUnit = GetCommandUnit(c, 0);
			const CFeature* reclaimeeFeature = NULL;

			if (c.IsAreaCommand()) { return true; }
			if (!ud->canReclaim) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; }

			if (reclaimeeUnit == NULL && !c.params.empty()) {
				const unsigned int reclaimeeFeatureID(c.params[0]);

				if (reclaimeeFeatureID >= uh->MaxUnits()) {
					reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - uh->MaxUnits());

					if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) {
						return false;
					}
				}
			}
		} break;

		case CMD_RESTORE: {
			if (!ud->canRestore || mapDamage->disabled) {
				return false;
			}
		} break;

		case CMD_RESURRECT: {
			if (!ud->canResurrect) { return false; }
		} break;

		case CMD_REPAIR: {
			const CUnit* repairee = GetCommandUnit(c, 0);

			if (!ud->canRepair && !ud->canAssist) { return false; }
			if (repairee && !repairee->pos.IsInBounds()) { return false; }
			if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; }
		} break;
	}


	if (cmd_id == CMD_FIRE_STATE
			&& (c.params.empty() || !CanChangeFireState()))
	{
		return false;
	}
	if (cmd_id == CMD_MOVE_STATE
			&& (c.params.empty() || (!ud->canmove && !ud->builder)))
	{
		return false;
	}
	if (cmd_id == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_TRAJECTORY
			&& (c.params.empty() || ud->highTrajectoryType < 2))
	{
		return false;
	}
	if (cmd_id == CMD_ONOFF
			&& (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmd_id == CMD_STOCKPILE && !stockpileWeapon)
	{
		return false;
	}
	return true;
}
Exemple #3
0
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced)
{
	const int cmdID = c.GetID();

	// TODO check if the command is in the map first, for more commands
	switch (cmdID) {
		case CMD_MOVE:
		case CMD_ATTACK:
		case CMD_AREA_ATTACK:
		case CMD_RECLAIM:
		case CMD_REPAIR:
		case CMD_RESURRECT:
		case CMD_PATROL:
		case CMD_RESTORE:
		case CMD_FIGHT:
		case CMD_MANUALFIRE:
		case CMD_UNLOAD_UNIT:
		case CMD_UNLOAD_UNITS: {
			if (!IsCommandInMap(c)) { return false; }
		} break;

		default: {
			// build commands
			if (cmdID < 0) {
				if (!IsCommandInMap(c))
					return false;

				const CBuilderCAI* bcai = dynamic_cast<const CBuilderCAI*>(this);
				const CFactoryCAI* fcai = dynamic_cast<const CFactoryCAI*>(this);

				// non-builders cannot ever execute these
				// we can get here if a factory is selected along with the
				// unit it is currently building and a build-order is given
				// to the former
				if (fcai == NULL && bcai == NULL)
					return false;

				// {Builder,Factory}CAI::GiveCommandReal (should) handle the
				// case where buildOptions.find(cmdID) == buildOptions.end()
			}
		} break;
	}


	const UnitDef* ud = owner->unitDef;
	// AI's may do as they like
	const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team);
	const bool aiOrder = (!saids.empty());

	switch (cmdID) {
		case CMD_MANUALFIRE:
			if (!ud->canManualFire)
				return false;
			// fall through

		case CMD_ATTACK: {
			if (!IsAttackCapable())
				return false;

			if (c.params.size() == 1) {
				const CUnit* attackee = GetCommandUnit(c, 0);

				if (attackee == NULL)
					return false;
				if (!attackee->pos.IsInBounds())
					return false;
			} else {
				if (c.params.size() >= 3) {
					const float3 cPos = c.GetPos(0);
					// FIXME: is fromSynced really sync-safe???
					// NOTE:
					//   uses gHeight = min(cPos.y, GetHeightAboveWater) instead
					//   of gHeight = GetHeightReal because GuiTraceRay can stop
					//   at water surface, so the attack-position would be moved
					//   UNDERWATER and cause ground-attack orders to fail
					// const float gHeight = std::min(cPos.y, ground->GetHeightAboveWater(cPos.x, cPos.z, fromSynced));
					const float gHeight = std::min(cPos.y, ground->GetHeightAboveWater(cPos.x, cPos.z, true));

					#if 0
					// check if attack-ground is really attack-ground
					//
					// NOTE:
					//     problematic if command contains value from UHM
					//     but is evaluated in synced context against SHM
					//     after roundtrip (when UHM and SHM differ a lot)
					//
					//     instead just clamp the elevation, which creates
					//     fewer issues overall (eg. artillery force-firing
					//     at positions outside LOS where UHM and SHM do not
					//     match will not be broken)
					//

					if (!aiOrder && math::fabs(cPos.y - gHeight) > SQUARE_SIZE) {
						return false;
					}
					#else
					if (!aiOrder) {
						Command& cc = const_cast<Command&>(c);
						cc.params[1] = gHeight;
					}

					return true;
					#endif
				}
			}
			break;
		}

		case CMD_MOVE:      if (!ud->canmove)       return false; break;
		case CMD_FIGHT:     if (!ud->canFight)      return false; break;
		case CMD_GUARD: {
			const CUnit* guardee = GetCommandUnit(c, 0);

			if (!ud->canGuard) { return false; }
			if (owner && !owner->pos.IsInBounds()) { return false; }
			if (guardee && !guardee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_PATROL: {
			if (!ud->canPatrol) { return false; }
		} break;

		case CMD_CAPTURE: {
			const CUnit* capturee = GetCommandUnit(c, 0);

			if (!ud->canCapture) { return false; }
			if (capturee && !capturee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_RECLAIM: {
			const CUnit* reclaimeeUnit = GetCommandUnit(c, 0);
			const CFeature* reclaimeeFeature = NULL;

			if (c.IsAreaCommand()) { return true; }
			if (!ud->canReclaim) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; }

			if (reclaimeeUnit == NULL && !c.params.empty()) {
				const unsigned int reclaimeeFeatureID(c.params[0]);

				if (reclaimeeFeatureID >= unitHandler->MaxUnits()) {
					reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - unitHandler->MaxUnits());

					if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) {
						return false;
					}
				}
			}
		} break;

		case CMD_RESTORE: {
			if (!ud->canRestore || mapDamage->disabled) {
				return false;
			}
		} break;

		case CMD_RESURRECT: {
			if (!ud->canResurrect) { return false; }
		} break;

		case CMD_REPAIR: {
			const CUnit* repairee = GetCommandUnit(c, 0);

			if (!ud->canRepair && !ud->canAssist) { return false; }
			if (repairee && !repairee->pos.IsInBounds()) { return false; }
			if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; }
		} break;
	}


	if (cmdID == CMD_FIRE_STATE
			&& (c.params.empty() || !CanChangeFireState()))
	{
		return false;
	}
	if (cmdID == CMD_MOVE_STATE
			&& (c.params.empty() || (!ud->canmove && !ud->builder)))
	{
		return false;
	}
	if (cmdID == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmdID == CMD_TRAJECTORY
			&& (c.params.empty() || ud->highTrajectoryType < 2))
	{
		return false;
	}
	if (cmdID == CMD_ONOFF
			&& (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmdID == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmdID == CMD_STOCKPILE && !stockpileWeapon)
	{
		return false;
	}
	return true;
}
bool CCommandAI::AllowedCommand(const Command& c, bool fromSynced)
{
	const int cmdID = c.GetID();

	// TODO check if the command is in the map first, for more commands
	switch (cmdID) {
		case CMD_MOVE:
		case CMD_ATTACK:
		case CMD_AREA_ATTACK:
		case CMD_RECLAIM:
		case CMD_REPAIR:
		case CMD_RESURRECT:
		case CMD_PATROL:
		case CMD_RESTORE:
		case CMD_FIGHT:
		case CMD_MANUALFIRE:
		case CMD_UNLOAD_UNIT:
		case CMD_UNLOAD_UNITS: {
			if (!IsCommandInMap(c)) {
				return false;
			}
		} break;

		default: {
			// build commands
			if (cmdID < 0) {
				if (!IsCommandInMap(c))
					return false;

				const CBuilderCAI* bcai = dynamic_cast<const CBuilderCAI*>(this);
				const CFactoryCAI* fcai = dynamic_cast<const CFactoryCAI*>(this);

				// non-builders cannot ever execute these
				// we can get here if a factory is selected along with the
				// unit it is currently building and a build-order is given
				// to the former
				if (fcai == NULL && bcai == NULL)
					return false;

				// {Builder,Factory}CAI::GiveCommandReal (should) handle the
				// case where buildOptions.find(cmdID) == buildOptions.end()
			}
		} break;
	}


	const UnitDef* ud = owner->unitDef;
	// AI's may do as they like
	const CSkirmishAIHandler::ids_t& saids = skirmishAIHandler.GetSkirmishAIsInTeam(owner->team);
	const bool aiOrder = (!saids.empty());

	switch (cmdID) {
		case CMD_MANUALFIRE:
			if (!ud->canManualFire)
				return false;
			// fall through

		case CMD_ATTACK: {
			if (!IsAttackCapable())
				return false;

			if (c.params.size() == 1) {
				const CUnit* attackee = GetCommandUnit(c, 0);

				if (attackee == NULL)
					return false;
				if (!attackee->pos.IsInBounds())
					return false;
			} else {
				AdjustGroundAttackCommand(c, fromSynced, aiOrder);
			}
			break;
		}

		case CMD_MOVE:      if (!ud->canmove)       return false; break;
		case CMD_FIGHT:     if (!ud->canFight)      return false; break;
		case CMD_GUARD: {
			const CUnit* guardee = GetCommandUnit(c, 0);

			if (!ud->canGuard) { return false; }
			if (owner && !owner->pos.IsInBounds()) { return false; }
			if (guardee && !guardee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_PATROL: {
			if (!ud->canPatrol) { return false; }
		} break;

		case CMD_CAPTURE: {
			const CUnit* capturee = GetCommandUnit(c, 0);

			if (!ud->canCapture) { return false; }
			if (capturee && !capturee->pos.IsInBounds()) { return false; }
		} break;

		case CMD_RECLAIM: {
			const CUnit* reclaimeeUnit = GetCommandUnit(c, 0);
			const CFeature* reclaimeeFeature = NULL;

			if (c.IsAreaCommand()) { return true; }
			if (!ud->canReclaim) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->unitDef->reclaimable) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->AllowedReclaim(owner)) { return false; }
			if (reclaimeeUnit && !reclaimeeUnit->pos.IsInBounds()) { return false; }

			if (reclaimeeUnit == NULL && !c.params.empty()) {
				const unsigned int reclaimeeFeatureID(c.params[0]);

				if (reclaimeeFeatureID >= unitHandler->MaxUnits()) {
					reclaimeeFeature = featureHandler->GetFeature(reclaimeeFeatureID - unitHandler->MaxUnits());

					if (reclaimeeFeature && !reclaimeeFeature->def->reclaimable) {
						return false;
					}
				}
			}
		} break;

		case CMD_RESTORE: {
			if (!ud->canRestore || mapDamage->disabled) {
				return false;
			}
		} break;

		case CMD_RESURRECT: {
			if (!ud->canResurrect) { return false; }
		} break;

		case CMD_REPAIR: {
			const CUnit* repairee = GetCommandUnit(c, 0);

			if (!ud->canRepair && !ud->canAssist) { return false; }
			if (repairee && !repairee->pos.IsInBounds()) { return false; }
			if (repairee && ((repairee->beingBuilt && !ud->canAssist) || (!repairee->beingBuilt && !ud->canRepair))) { return false; }
		} break;
	}


	if (cmdID == CMD_FIRE_STATE
			&& (c.params.empty() || !CanChangeFireState()))
	{
		return false;
	}
	if (cmdID == CMD_MOVE_STATE
			&& (c.params.empty() || (!ud->canmove && !ud->builder)))
	{
		return false;
	}
	if (cmdID == CMD_REPEAT && (c.params.empty() || !ud->canRepeat || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmdID == CMD_TRAJECTORY
			&& (c.params.empty() || ud->highTrajectoryType < 2))
	{
		return false;
	}
	if (cmdID == CMD_ONOFF
			&& (c.params.empty() || !ud->onoffable || owner->beingBuilt || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmdID == CMD_CLOAK && (c.params.empty() || !ud->canCloak || ((int)c.params[0] % 2) != (int)c.params[0]/* only 0 or 1 allowed */))
	{
		return false;
	}
	if (cmdID == CMD_STOCKPILE && !stockpileWeapon)
	{
		return false;
	}
	return true;
}