/* Make droid/structure look for a better target */ static BOOL updateAttackTarget(BASE_OBJECT * psAttacker, SDWORD weapon_slot) { BASE_OBJECT *psBetterTarget=NULL; UWORD tmpOrigin = ORIGIN_UNKNOWN; if(aiChooseTarget(psAttacker, &psBetterTarget, weapon_slot, true, &tmpOrigin)) //update target { if(psAttacker->type == OBJ_DROID) { DROID *psDroid = (DROID *)psAttacker; if( (orderState(psDroid, DORDER_NONE) || orderState(psDroid, DORDER_GUARD) || orderState(psDroid, DORDER_ATTACKTARGET)) && weapon_slot == 0) //Watermelon:only primary slot(0) updates affect order { orderDroidObj((DROID *)psAttacker, DORDER_ATTACKTARGET, psBetterTarget); } else //can't override current order { setDroidActionTarget(psDroid, psBetterTarget, weapon_slot); } } else if (psAttacker->type == OBJ_STRUCTURE) { STRUCTURE *psBuilding = (STRUCTURE *)psAttacker; setStructureTarget(psBuilding, psBetterTarget, weapon_slot, tmpOrigin); } return true; } return false; }
/* Make droid/structure look for a better target */ static bool updateAttackTarget(BASE_OBJECT *psAttacker, SDWORD weapon_slot) { BASE_OBJECT *psBetterTarget = NULL; TARGET_ORIGIN tmpOrigin = ORIGIN_UNKNOWN; if (aiChooseTarget(psAttacker, &psBetterTarget, weapon_slot, true, &tmpOrigin)) //update target { if (psAttacker->type == OBJ_DROID) { DROID *psDroid = (DROID *)psAttacker; if ((orderState(psDroid, DORDER_NONE) || orderState(psDroid, DORDER_GUARD) || orderState(psDroid, DORDER_ATTACKTARGET)) && weapon_slot == 0) { actionDroid((DROID *)psAttacker, DACTION_ATTACK, psBetterTarget); } else //can't override current order { setDroidActionTarget(psDroid, psBetterTarget, weapon_slot); } } else if (psAttacker->type == OBJ_STRUCTURE) { STRUCTURE *psBuilding = (STRUCTURE *)psAttacker; setStructureTarget(psBuilding, psBetterTarget, weapon_slot, tmpOrigin); } return true; } return false; }
/* 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); } } } }
/* 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); } } } }
/* Updates the camera's point of interest if it's time to */ void processDemoCam( void ) { UDWORD firstPlayer,otherPlayer; DROID *psDroid; BOOL bSkipOrder = false; UDWORD i,numWith; /* Is the demo camera actually active? */ if(presentStatus == DC_INACTIVE) { /* Nope, so get out */ return; } /* Is it time for a new target? */ if( gameTime > (lastCameraMove + demoCamInterval) ) { lastCameraMove = gameTime; /* The bones */ findSomethingInteresting(); // player.r.x = DEG(-90); } /* Otherwise, just send a droid off to war */ else if(gameTime > (lastDroidSending + GAME_TICKS_PER_SEC) ) { /* Check all the droid lists, looking for empty ones */ for(i = 0,numWith = 0; i<MAX_PLAYERS; i++) { /* Keep a count of how many are empty */ if(apsDroidLists[i]) { /* We got one */ numWith++; } } /* If they were all empty, then record this fact and only seek locations */ /* We need two sides for this to work! */ if(numWith<2) { bSkipOrder = true; } if(!bSkipOrder) { lastDroidSending = gameTime; /* Choose a player at random */ firstPlayer = rand()%MAX_PLAYERS; /* Have they got any droids? */ while(apsDroidLists[firstPlayer]==NULL) { /* Nope, so choose another one until we get one with droids */ firstPlayer = rand()%MAX_PLAYERS; } /* Choose a player at random */ otherPlayer = rand()%MAX_PLAYERS; /* Have they got any structures? Make sure it's not their own we're checking! */ while(apsStructLists[otherPlayer]==NULL || otherPlayer==firstPlayer) { /* Nope, so choose another one until we get one with droids */ otherPlayer = rand()%MAX_PLAYERS; } psDroid = getDroidForDemo(firstPlayer); /* Only do this if we've got a droid and an enemy building to attack! */ if(psDroid && apsStructLists[otherPlayer]) { if( (orderState(psDroid,DORDER_NONE) == true) || ((orderState(psDroid,DORDER_GUARD) == true) && (psDroid->action == DACTION_NONE))) { /* Make the droid attack the building - it'll indirectly route there too */ orderDroidLoc(psDroid,DORDER_SCOUT, apsStructLists[otherPlayer]->pos.x, apsStructLists[otherPlayer]->pos.y, ModeQueue); } } } } }