Exemple #1
0
// return the state for an order for all the units selected
// if there are multiple states then don't return a state
static SECONDARY_STATE GetSecondaryStates(SECONDARY_ORDER sec)
{
	SECONDARY_STATE state, currState;
	bool	bFirst;

	state = (SECONDARY_STATE)0;
	bFirst = true;
	if (psSelectedFactory)
	{
		if (getFactoryState(psSelectedFactory, sec, &currState))
		{
			state = currState;
		}
	}
	else //droids
	{
		for (unsigned i = 0; i < SelectedDroids.size(); ++i)
		{
			currState = secondaryGetState(SelectedDroids[i], sec, ModeQueue);
			if (bFirst)
			{
				state = currState;
				bFirst = false;
			}
			else if (state != currState)
			{
				state = (SECONDARY_STATE)0;
			}
		}
	}

	return state;
}
Exemple #2
0
/* Do the AI for a droid */
void aiUpdateDroid(DROID *psDroid)
{
	BASE_OBJECT	*psTarget;
	BOOL		lookForTarget,updateTarget;

	ASSERT(psDroid != NULL, "Invalid droid pointer");
	if (!psDroid || isDead((BASE_OBJECT *)psDroid))
	{
		return;
	}

	// HACK: we always want to update orders when NOT running a MP game,
	// and we don't want to update when the droid belongs to another human player
	if (!myResponsibility(psDroid->player) && bMultiPlayer
		  && isHumanPlayer(psDroid->player))
	{
		return;		// we should not order this droid around
	}
	
	lookForTarget = false;
	updateTarget = false;
	
	// look for a target if doing nothing
	if (orderState(psDroid, DORDER_NONE) ||
		orderState(psDroid, DORDER_GUARD) ||
		orderState(psDroid, DORDER_TEMP_HOLD))
	{
		lookForTarget = true;
	}
	// but do not choose another target if doing anything while guarding
	if (orderState(psDroid, DORDER_GUARD) &&
		(psDroid->action != DACTION_NONE))
	{
		lookForTarget = false;
	}
	// except when self-repairing
	if (psDroid->action == DACTION_DROIDREPAIR &&
	    psDroid->psActionTarget[0] == (BASE_OBJECT *)psDroid)
	{
		lookForTarget = true;
	}
	// don't look for a target if sulking
	if (psDroid->action == DACTION_SULK)
	{
		lookForTarget = false;
	}

	/* Only try to update target if already have some target */
	if (psDroid->action == DACTION_ATTACK ||
		psDroid->action == DACTION_MOVEFIRE ||
		psDroid->action == DACTION_MOVETOATTACK ||
		psDroid->action == DACTION_ROTATETOATTACK)
	{
		updateTarget = true;
	}
	if ((orderState(psDroid, DORDER_OBSERVE) || orderState(psDroid, DORDER_ATTACKTARGET)) &&
	    psDroid->psTarget && aiObjectIsProbablyDoomed(psDroid->psTarget))
	{
		lookForTarget = true;
		updateTarget = false;
	}

	/* Don't update target if we are sent to attack and reached
		attack destination (attacking our target) */
	if (orderState(psDroid, DORDER_ATTACK) && psDroid->psActionTarget[0] == psDroid->psTarget)
	{
		updateTarget = false;
	}

	// don't look for a target if there are any queued orders
	if (psDroid->listSize > 0)
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// horrible check to stop droids looking for a target if
	// they would switch to the guard order in the order update loop
	if ((psDroid->order == DORDER_NONE) &&
		(psDroid->player == selectedPlayer) &&
		!isVtolDroid(psDroid) &&
		secondaryGetState(psDroid, DSO_HALTTYPE) == DSS_HALT_GUARD)
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// don't allow units to start attacking if they will switch to guarding the commander
	if(hasCommander(psDroid))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	if(bMultiPlayer && isVtolDroid(psDroid) && isHumanPlayer(psDroid->player))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// do not look for a target if droid is currently under direct control.
	if(driveModeActive() && (psDroid == driveGetDriven())) {
		lookForTarget = false;
		updateTarget = false;
	}

	// CB and VTOL CB droids can't autotarget.
	if (psDroid->droidType == DROID_SENSOR && !standardSensorDroid(psDroid))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// do not attack if the attack level is wrong
	if (secondaryGetState(psDroid, DSO_ATTACK_LEVEL) != DSS_ALEV_ALWAYS)
	{
		lookForTarget = false;
	}

	/* For commanders and non-assigned non-commanders:
	 look for a better target once in a while */
	if(!lookForTarget && updateTarget)
	{
		if((psDroid->numWeaps > 0) && !hasCommander(psDroid))	//not assigned to commander
		{
			if((psDroid->id + gameTime)/TARGET_UPD_SKIP_FRAMES != (psDroid->id + gameTime - deltaGameTime)/TARGET_UPD_SKIP_FRAMES)
			{
				unsigned int i;

				(void)updateAttackTarget((BASE_OBJECT*)psDroid, 0); // this function always has to be called on weapon-slot 0 (even if ->numWeaps == 0)

				//updates all targets
				for (i = 1; i < psDroid->numWeaps; ++i)
				{
					(void)updateAttackTarget((BASE_OBJECT*)psDroid, i);
				}
			}
		}
	}

	/* Null target - see if there is an enemy to attack */

	if (lookForTarget && !updateTarget)
	{
		if (psDroid->droidType == DROID_SENSOR)
		{
			if (aiChooseSensorTarget((BASE_OBJECT *)psDroid, &psTarget))
			{
				orderDroidObj(psDroid, DORDER_OBSERVE, psTarget);
			}
		}
		else
		{
			if (aiChooseTarget((BASE_OBJECT *)psDroid, &psTarget, 0, true, NULL))
			{
				orderDroidObj(psDroid, DORDER_ATTACKTARGET, psTarget);
			}
		}
	}
}
Exemple #3
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;
}
Exemple #4
0
/* Do the AI for a droid */
void aiUpdateDroid(DROID *psDroid)
{
	BASE_OBJECT	*psTarget;
	bool		lookForTarget, updateTarget;

	ASSERT(psDroid != NULL, "Invalid droid pointer");
	if (!psDroid || isDead((BASE_OBJECT *)psDroid))
	{
		return;
	}

	lookForTarget = false;
	updateTarget = false;

	// look for a target if doing nothing
	if (orderState(psDroid, DORDER_NONE) ||
	    orderState(psDroid, DORDER_GUARD) ||
	    orderState(psDroid, DORDER_HOLD))
	{
		lookForTarget = true;
	}
	// but do not choose another target if doing anything while guarding
	// exception for sensors, to allow re-targetting when target is doomed
	if (orderState(psDroid, DORDER_GUARD) && psDroid->action != DACTION_NONE && psDroid->droidType != DROID_SENSOR)
	{
		lookForTarget = false;
	}
	// don't look for a target if sulking
	if (psDroid->action == DACTION_SULK)
	{
		lookForTarget = false;
	}

	/* Only try to update target if already have some target */
	if (psDroid->action == DACTION_ATTACK ||
	    psDroid->action == DACTION_MOVEFIRE ||
	    psDroid->action == DACTION_MOVETOATTACK ||
	    psDroid->action == DACTION_ROTATETOATTACK)
	{
		updateTarget = true;
	}
	if ((orderState(psDroid, DORDER_OBSERVE) || orderState(psDroid, DORDER_ATTACKTARGET)) &&
	    psDroid->order.psObj && psDroid->order.psObj->died)
	{
		lookForTarget = true;
		updateTarget = false;
	}

	/* Don't update target if we are sent to attack and reached attack destination (attacking our target) */
	if (orderState(psDroid, DORDER_ATTACK) && psDroid->psActionTarget[0] == psDroid->order.psObj)
	{
		updateTarget = false;
	}

	// don't look for a target if there are any queued orders
	if (psDroid->listSize > 0)
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// don't allow units to start attacking if they will switch to guarding the commander
	if (hasCommander(psDroid))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	if (bMultiPlayer && isVtolDroid(psDroid) && isHumanPlayer(psDroid->player))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// do not look for a target if droid is currently under direct control.
	if (driveModeActive() && (psDroid == driveGetDriven()))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// CB and VTOL CB droids can't autotarget.
	if (psDroid->droidType == DROID_SENSOR && !standardSensorDroid(psDroid))
	{
		lookForTarget = false;
		updateTarget = false;
	}

	// do not attack if the attack level is wrong
	if (secondaryGetState(psDroid, DSO_ATTACK_LEVEL) != DSS_ALEV_ALWAYS)
	{
		lookForTarget = false;
	}

	/* For commanders and non-assigned non-commanders: look for a better target once in a while */
	if (!lookForTarget && updateTarget && psDroid->numWeaps > 0 && !hasCommander(psDroid)
	    && (psDroid->id + gameTime) / TARGET_UPD_SKIP_FRAMES != (psDroid->id + gameTime - deltaGameTime) / TARGET_UPD_SKIP_FRAMES)
	{
		for (int i = 0; i < psDroid->numWeaps; ++i)
		{
			updateAttackTarget((BASE_OBJECT *)psDroid, i);
		}
	}

	/* Null target - see if there is an enemy to attack */

	if (lookForTarget && !updateTarget)
	{
		if (psDroid->droidType == DROID_SENSOR)
		{
			if (aiChooseSensorTarget((BASE_OBJECT *)psDroid, &psTarget))
			{
				actionDroid(psDroid, DACTION_OBSERVE, psTarget);
			}
		}
		else
		{
			if (aiChooseTarget((BASE_OBJECT *)psDroid, &psTarget, 0, true, NULL))
			{
				actionDroid(psDroid, DACTION_ATTACK, psTarget);
			}
		}
	}
}