Пример #1
0
int CCommandAI::GetDefaultCmd(const CUnit* pointed, const CFeature* feature)
{
	if (pointed) {
		if (!teamHandler->Ally(gu->myAllyTeam, pointed->allyteam)) {
			if (IsAttackCapable()) {
				return CMD_ATTACK;
			}
		}
	}
	return CMD_STOP;
}
Пример #2
0
CCommandAI::CCommandAI(CUnit* owner):
	stockpileWeapon(0),
	lastUserCommand(-1000),
	selfDCountdown(0),
	lastFinishCommand(0),
	owner(owner),
	orderTarget(0),
	targetDied(false),
	inCommand(false),
	selected(false),
	repeatOrders(false),
	lastSelectedCommandPage(0),
	unimportantMove(false),
	targetLostTimer(TARGET_LOST_TIMER)
{
	owner->commandAI = this;
	CommandDescription c;
	c.id = CMD_STOP;
	c.action = "stop";
	c.type = CMDTYPE_ICON;
	c.name = "Stop";
	c.mouseicon = c.name;
	c.tooltip = "Stop: Cancel the units current actions";
	possibleCommands.push_back(c);

	if (IsAttackCapable()) {
		c.id = CMD_ATTACK;
		c.action = "attack";
		c.type = CMDTYPE_ICON_UNIT_OR_MAP;
		c.name = "Attack";
		c.mouseicon = c.name;
		c.tooltip = "Attack: Attacks a unit or a position on the ground";
		possibleCommands.push_back(c);
	}

	if (owner->unitDef->canManualFire) {
		c.id = CMD_MANUALFIRE;
		c.action = "manualfire";
		c.type = CMDTYPE_ICON_MAP;
		c.name = "ManualFire";
		c.mouseicon = c.name;
		c.tooltip = "ManualFire: Attacks with manually-fired weapon";
		possibleCommands.push_back(c);
	}

	c.id = CMD_WAIT;
	c.action = "wait";
	c.type = CMDTYPE_ICON;
	c.name = "Wait";
	c.mouseicon = c.name;
	c.tooltip = "Wait: Tells the unit to wait until another units handles it";
	possibleCommands.push_back(c);
//	nonQueingCommands.insert(CMD_WAIT);

	c.id = CMD_TIMEWAIT;
	c.action = "timewait";
	c.type = CMDTYPE_NUMBER;
	c.name = "TimeWait";
	c.mouseicon=c.name;
	c.tooltip = "TimeWait: Wait for a period of time before continuing";
	c.params.push_back("1");  // min
	c.params.push_back("60"); // max
	c.hidden = true;
	possibleCommands.push_back(c);
	c.hidden = false;
	c.params.clear();

	// only for games with 2 ally teams  --  checked later
	c.id = CMD_DEATHWAIT;
	c.action = "deathwait";
	c.type = CMDTYPE_ICON_UNIT_OR_RECTANGLE;
	c.name = "DeathWait";
	c.mouseicon=c.name;
	c.tooltip = "DeathWait: Wait until units die before continuing";
	c.hidden = true;
	possibleCommands.push_back(c);
	c.hidden = false;

	c.id = CMD_SQUADWAIT;
	c.action = "squadwait";
	c.type = CMDTYPE_NUMBER;
	c.name = "SquadWait";
	c.mouseicon=c.name;
	c.tooltip = "SquadWait: Wait for a number of units to arrive before continuing";
	c.params.push_back("2");   // min
	c.params.push_back("100"); // max
	c.hidden = true;
	possibleCommands.push_back(c);
	c.hidden = false;
	c.params.clear();

	c.id = CMD_GATHERWAIT;
	c.action = "gatherwait";
	c.type = CMDTYPE_ICON;
	c.name = "GatherWait";
	c.mouseicon=c.name;
	c.tooltip = "GatherWait: Wait until all units arrive before continuing";
	c.hidden = true;
	possibleCommands.push_back(c);
	c.hidden = false;

	if (owner->unitDef->canSelfD) {
		c.id = CMD_SELFD;
		c.action = "selfd";
		c.type = CMDTYPE_ICON;
		c.name = "SelfD";
		c.mouseicon = c.name;
		c.tooltip = "SelfD: Tells the unit to self destruct";
		c.hidden = true;
		possibleCommands.push_back(c);
		c.hidden = false;
	}
//	nonQueingCommands.insert(CMD_SELFD);

	if(CanChangeFireState()) {
		c.id = CMD_FIRE_STATE;
		c.action = "firestate";
		c.type = CMDTYPE_ICON_MODE;
		c.name = "Fire state";
		c.mouseicon = c.name;
		c.params.push_back(IntToString(FIRESTATE_FIREATWILL));
		c.params.push_back("Hold fire");
		c.params.push_back("Return fire");
		c.params.push_back("Fire at will");
		c.tooltip = "Fire State: Sets under what conditions an\n unit will start to fire at enemy units\n without an explicit attack order";
		possibleCommands.push_back(c);
		nonQueingCommands.insert(CMD_FIRE_STATE);
	}

	if (owner->unitDef->canmove || owner->unitDef->builder) {
		c.params.clear();
		c.id = CMD_MOVE_STATE;
		c.action = "movestate";
		c.type = CMDTYPE_ICON_MODE;
		c.name = "Move state";
		c.mouseicon = c.name;
		c.params.push_back(IntToString(MOVESTATE_MANEUVER));
		c.params.push_back("Hold pos");
		c.params.push_back("Maneuver");
		c.params.push_back("Roam");
		c.tooltip = "Move State: Sets how far out of its way\n an unit will move to attack enemies";
		possibleCommands.push_back(c);
		nonQueingCommands.insert(CMD_MOVE_STATE);
	} else {
		owner->moveState = MOVESTATE_HOLDPOS;
	}

	if (owner->unitDef->canRepeat) {
		c.params.clear();
		c.id = CMD_REPEAT;
		c.action = "repeat";
		c.type = CMDTYPE_ICON_MODE;
		c.name = "Repeat";
		c.mouseicon = c.name;
		c.params.push_back("0");
		c.params.push_back("Repeat off");
		c.params.push_back("Repeat on");
		c.tooltip = "Repeat: If on the unit will continously\n push finished orders to the end of its\n order queue";
		possibleCommands.push_back(c);
		nonQueingCommands.insert(CMD_REPEAT);
	}

	if (owner->unitDef->highTrajectoryType>1) {
		c.params.clear();
		c.id = CMD_TRAJECTORY;
		c.action = "trajectory";
		c.type = CMDTYPE_ICON_MODE;
		c.name = "Trajectory";
		c.mouseicon = c.name;
		c.params.push_back("0");
		c.params.push_back("Low traj");
		c.params.push_back("High traj");
		c.tooltip = "Trajectory: If set to high, weapons that\n support it will try to fire in a higher\n trajectory than usual (experimental)";
		possibleCommands.push_back(c);
		nonQueingCommands.insert(CMD_TRAJECTORY);
	}

	if (owner->unitDef->onoffable) {
		c.params.clear();
		c.id = CMD_ONOFF;
		c.action = "onoff";
		c.type = CMDTYPE_ICON_MODE;
		c.name = "Active state";
		c.mouseicon = c.name;

		if (owner->unitDef->activateWhenBuilt) {
			c.params.push_back("1");
		} else {
			c.params.push_back("0");
		}

		c.params.push_back(" Off ");
		c.params.push_back(" On ");

		c.tooltip = "Active State: Sets the active state of the unit to on or off";
		possibleCommands.push_back(c);
		nonQueingCommands.insert(CMD_ONOFF);
	}

	if (owner->unitDef->canCloak) {
		c.params.clear();
		c.id = CMD_CLOAK;
		c.action = "cloak";
		c.type = CMDTYPE_ICON_MODE;
		c.name = "Cloak state";
		c.mouseicon = c.name;

		if (owner->unitDef->startCloaked) {
			c.params.push_back("1");
		} else {
			c.params.push_back("0");
		}

		c.params.push_back("UnCloaked");
		c.params.push_back("Cloaked");

		c.tooltip = "Cloak State: Sets whether the unit is cloaked or not";
		possibleCommands.push_back(c);
		nonQueingCommands.insert(CMD_CLOAK);
	}
}
Пример #3
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;
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
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 {
				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;
}