Example #1
0
/* See if there is a target in range */
BOOL aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot, BOOL bUpdateTarget, UWORD *targetOrigin)
{
	BASE_OBJECT		*psTarget = NULL;
	DROID			*psCommander;
	SDWORD			curTargetWeight=-1;
	UWORD 			tmpOrigin = ORIGIN_UNKNOWN;

	if (targetOrigin)
	{
		*targetOrigin = ORIGIN_UNKNOWN;
	}
		
	/* Get the sensor range */
	switch (psObj->type)
	{
	case OBJ_DROID:
		if (((DROID *)psObj)->asWeaps[weapon_slot].nStat == 0)
		{
			return false;
		}

		if (((DROID *)psObj)->asWeaps[0].nStat == 0 &&
			((DROID *)psObj)->droidType != DROID_SENSOR)
		{
			// Can't attack without a weapon
			return false;
		}
		break;
	case OBJ_STRUCTURE:
		if (((STRUCTURE *)psObj)->numWeaps == 0 || ((STRUCTURE *)psObj)->asWeaps[0].nStat == 0)
		{
			// Can't attack without a weapon
			return false;
		}
		break;
	default:
		break;
	}

	/* See if there is a something in range */
	if (psObj->type == OBJ_DROID)
	{
		BASE_OBJECT *psCurrTarget = ((DROID *)psObj)->psActionTarget[0];

		/* find a new target */
		int newTargetWeight = aiBestNearestTarget((DROID *)psObj, &psTarget, weapon_slot, NULL);

		/* Calculate weight of the current target if updating; but take care not to target
		 * ourselves... */
		if (bUpdateTarget && psCurrTarget != psObj)
		{
			curTargetWeight = targetAttackWeight(psCurrTarget, psObj, weapon_slot);
		}

		if (newTargetWeight >= 0		// found a new target
		    && (!bUpdateTarget			// choosing a new target, don't care if current one is better
		        || curTargetWeight <= 0		// attacker had no valid target, use new one
			|| newTargetWeight > curTargetWeight + OLD_TARGET_THRESHOLD)	// updating and new target is better
		    && validTarget(psObj, psTarget, weapon_slot)
		    && (aiDroidHasRange((DROID *)psObj, psTarget, weapon_slot) || (secondaryGetState((DROID *)psObj, DSO_HALTTYPE) != DSS_HALT_HOLD)))
		{
			ASSERT(!isDead(psTarget), "aiChooseTarget: Droid found a dead target!");
			*ppsTarget = psTarget;
			return true;
		}
	}
	else if (psObj->type == OBJ_STRUCTURE)
	{
		WEAPON_STATS	*psWStats = NULL;
		int	tarDist, longRange = 0;
		BOOL	bCommanderBlock = false;

		ASSERT(((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat > 0, "no weapons on structure");

		psWStats = ((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat + asWeaponStats;
		longRange = proj_GetLongRange(psWStats);

		// see if there is a target from the command droids
		psTarget = NULL;
		psCommander = cmdDroidGetDesignator(psObj->player);
		if (!proj_Direct(psWStats) && (psCommander != NULL) &&
			aiStructHasRange((STRUCTURE *)psObj, (BASE_OBJECT *)psCommander, weapon_slot))
		{
			// there is a commander that can fire designate for this structure
			// set bCommanderBlock so that the structure does not fire until the commander
			// has a target - (slow firing weapons will not be ready to fire otherwise).
			bCommanderBlock = true;

			// I do believe this will never happen, check for yourself :-)
			debug(LOG_NEVER,"Commander %d is good enough for fire designation", psCommander->id);

			if (psCommander->action == DACTION_ATTACK
			    && psCommander->psActionTarget[0] != NULL
			    && !aiObjectIsProbablyDoomed(psCommander->psActionTarget[0]))
			{
				// the commander has a target to fire on
				if (aiStructHasRange((STRUCTURE *)psObj, psCommander->psActionTarget[0], weapon_slot))
				{
					// target in range - fire on it
					tmpOrigin = ORIGIN_COMMANDER;
					psTarget = psCommander->psActionTarget[0];
				}
				else
				{
					// target out of range - release the commander block
					bCommanderBlock = false;
				}
			}
		}

		// indirect fire structures use sensor towers first
		tarDist = longRange * longRange;
		if (psTarget == NULL && !bCommanderBlock && !proj_Direct(psWStats))
		{
			psTarget = aiSearchSensorTargets(psObj, weapon_slot, psWStats, &tmpOrigin);
		}

		if (psTarget == NULL && !bCommanderBlock)
		{
			BASE_OBJECT *psCurr;

			gridStartIterate(psObj->pos.x, psObj->pos.y, PREVIOUS_DEFAULT_GRID_SEARCH_RADIUS);
			psCurr = gridIterate();
			while (psCurr != NULL)
			{
				/* Check that it is a valid target */
				if (psCurr->type != OBJ_FEATURE && !aiObjectIsProbablyDoomed(psCurr) && aiStructHasRange((STRUCTURE *)psObj, psCurr, weapon_slot)
				    && !aiCheckAlliances(psCurr->player, psObj->player)
				    && validTarget(psObj, psCurr, weapon_slot) && psCurr->visible[psObj->player])
				{
					// See if in sensor range and visible
					int distSq = objPosDiffSq(psCurr->pos, psObj->pos);

					if (distSq < tarDist
					    || (psTarget && psTarget->type == OBJ_STRUCTURE && ((STRUCTURE *)psTarget)->status != SS_BUILT)
					    || (psTarget && aiObjIsWall(psTarget) && !aiObjIsWall(psCurr)))
					{
						tmpOrigin = ORIGIN_VISUAL;
						psTarget = psCurr;
						tarDist = distSq;
					}
				}
				psCurr = gridIterate();
			}
		}

		if (psTarget)
		{
			ASSERT(!psTarget->died, "aiChooseTarget: Structure found a dead target!");
			if (targetOrigin)
			{
				*targetOrigin = tmpOrigin;
			}
			*ppsTarget = psTarget;
			return true;
		}
	}

	return false;
}
Example #2
0
/* See if there is a target in range */
bool aiChooseTarget(BASE_OBJECT *psObj, BASE_OBJECT **ppsTarget, int weapon_slot, bool bUpdateTarget, TARGET_ORIGIN *targetOrigin)
{
	BASE_OBJECT		*psTarget = NULL;
	DROID			*psCommander;
	SDWORD			curTargetWeight = -1;
	TARGET_ORIGIN		tmpOrigin = ORIGIN_UNKNOWN;

	if (targetOrigin)
	{
		*targetOrigin = ORIGIN_UNKNOWN;
	}

	switch (psObj->type)
	{
	case OBJ_DROID:
		if (((DROID *)psObj)->asWeaps[weapon_slot].nStat == 0)
		{
			return false;
		}
		if (((DROID *)psObj)->asWeaps[0].nStat == 0 &&
		    ((DROID *)psObj)->droidType != DROID_SENSOR)
		{
			return false;	// Can't target without a weapon or sensor
		}
		break;
	case OBJ_STRUCTURE:
		if (((STRUCTURE *)psObj)->numWeaps == 0 || ((STRUCTURE *)psObj)->asWeaps[0].nStat == 0)
		{
			// Can't attack without a weapon
			return false;
		}
		break;
	default:
		break;
	}

	/* See if there is a something in range */
	if (psObj->type == OBJ_DROID)
	{
		BASE_OBJECT *psCurrTarget = ((DROID *)psObj)->psActionTarget[0];

		/* find a new target */
		int newTargetWeight = aiBestNearestTarget((DROID *)psObj, &psTarget, weapon_slot);

		/* Calculate weight of the current target if updating; but take care not to target
		 * ourselves... */
		if (bUpdateTarget && psCurrTarget != psObj)
		{
			curTargetWeight = targetAttackWeight(psCurrTarget, psObj, weapon_slot);
		}

		if (newTargetWeight >= 0		// found a new target
		    && (!bUpdateTarget			// choosing a new target, don't care if current one is better
		        || curTargetWeight <= 0		// attacker had no valid target, use new one
		        || newTargetWeight > curTargetWeight + OLD_TARGET_THRESHOLD)	// updating and new target is better
		    && validTarget(psObj, psTarget, weapon_slot)
		    && aiDroidHasRange((DROID *)psObj, psTarget, weapon_slot))
		{
			ASSERT(!isDead(psTarget), "Droid found a dead target!");
			*ppsTarget = psTarget;
			return true;
		}
	}
	else if (psObj->type == OBJ_STRUCTURE)
	{
		WEAPON_STATS	*psWStats = NULL;
		bool	bCommanderBlock = false;

		ASSERT(((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat > 0, "no weapons on structure");

		psWStats = ((STRUCTURE *)psObj)->asWeaps[weapon_slot].nStat + asWeaponStats;
		int longRange = proj_GetLongRange(psWStats, psObj->player);

		// see if there is a target from the command droids
		psTarget = NULL;
		psCommander = cmdDroidGetDesignator(psObj->player);
		if (!proj_Direct(psWStats) && (psCommander != NULL) &&
		    aiStructHasRange((STRUCTURE *)psObj, (BASE_OBJECT *)psCommander, weapon_slot))
		{
			// there is a commander that can fire designate for this structure
			// set bCommanderBlock so that the structure does not fire until the commander
			// has a target - (slow firing weapons will not be ready to fire otherwise).
			bCommanderBlock = true;

			// I do believe this will never happen, check for yourself :-)
			debug(LOG_NEVER, "Commander %d is good enough for fire designation", psCommander->id);

			if (psCommander->action == DACTION_ATTACK
			    && psCommander->psActionTarget[0] != NULL
			    && !psCommander->psActionTarget[0]->died)
			{
				// the commander has a target to fire on
				if (aiStructHasRange((STRUCTURE *)psObj, psCommander->psActionTarget[0], weapon_slot))
				{
					// target in range - fire on it
					tmpOrigin = ORIGIN_COMMANDER;
					psTarget = psCommander->psActionTarget[0];
				}
				else
				{
					// target out of range - release the commander block
					bCommanderBlock = false;
				}
			}
		}

		// indirect fire structures use sensor towers first
		if (psTarget == NULL && !bCommanderBlock && !proj_Direct(psWStats))
		{
			psTarget = aiSearchSensorTargets(psObj, weapon_slot, psWStats, &tmpOrigin);
		}

		if (psTarget == NULL && !bCommanderBlock)
		{
			int targetValue = -1;
			int tarDist = INT32_MAX;
			int srange = longRange;

			if (!proj_Direct(psWStats) && srange > objSensorRange(psObj))
			{
				// search radius of indirect weapons limited by their sight, unless they use
				// external sensors to provide fire designation
				srange = objSensorRange(psObj);
			}

			static GridList gridList;  // static to avoid allocations.
			gridList = gridStartIterate(psObj->pos.x, psObj->pos.y, srange);
			for (GridIterator gi = gridList.begin(); gi != gridList.end(); ++gi)
			{
				BASE_OBJECT *psCurr = *gi;
				/* Check that it is a valid target */
				if (psCurr->type != OBJ_FEATURE && !psCurr->died
				    && !aiCheckAlliances(psCurr->player, psObj->player)
				    && validTarget(psObj, psCurr, weapon_slot) && psCurr->visible[psObj->player] == UBYTE_MAX
				    && aiStructHasRange((STRUCTURE *)psObj, psCurr, weapon_slot))
				{
					int newTargetValue = targetAttackWeight(psCurr, psObj, weapon_slot);
					// See if in sensor range and visible
					int distSq = objPosDiffSq(psCurr->pos, psObj->pos);
					if (newTargetValue < targetValue || (newTargetValue == targetValue && distSq >= tarDist))
					{
						continue;
					}

					tmpOrigin = ORIGIN_VISUAL;
					psTarget = psCurr;
					tarDist = distSq;
					targetValue = newTargetValue;
				}
			}
		}

		if (psTarget)
		{
			ASSERT(!psTarget->died, "Structure found a dead target!");
			if (targetOrigin)
			{
				*targetOrigin = tmpOrigin;
			}
			*ppsTarget = psTarget;
			return true;
		}
	}

	return false;
}