sdword aimProcessFancyGetShips(AITeam *team) { AITeamMove *thisMove = team->curMove; AIVar *doneVar; char label[AIVAR_LABEL_MAX_LENGTH+1]; sdword numShipsToBuild, numShipsToGet; if (!thisMove->processing) { ShipType shiptype = thisMove->params.fancyGetShips.shipType; sdword numPointsLeftToGet = thisMove->params.fancyGetShips.numShips * ALTERNATIVE_SHIP_BASE; AlternativeShips *alternativeShips = &thisMove->params.fancyGetShips.alternatives; sdword numAlternatives = alternativeShips->numNextPicks; sdword i; doneVar = aivarCreate(aivarLabelGenerate(label)); aivarValueSet(doneVar, 0); thisMove->params.fancyGetShips.doneVar = doneVar; // try to get as many of the requested ships as possible: // if any types are unavailable due to research, add check here later GetFromReservesShipsOfShipType(team,shiptype,ALTERNATIVE_SHIP_BASE,&numPointsLeftToGet); // now try alternatives for (i=0;i<numAlternatives;i++) { if (numPointsLeftToGet <= 0) { break; } GetFromReservesShipsOfShipType(team,alternativeShips->shipTypeNextPicks[i],alternativeShips->shipNumEquivNextPicks[i],&numPointsLeftToGet); } if (numPointsLeftToGet > 0) { // we couldn't get enough from reserves, so we have to build the rest: if (alternativeShips->alternativeFlags & ALTERNATIVE_RANDOM) { // randomly pick the rest sdword j; udword randomnum = ranRandom(RAN_AIPlayer) % (numAlternatives+1); if (randomnum == 0) { goto buildbaseshiporfirst; } randomnum--; dbgAssert(randomnum < numAlternatives); for (i=randomnum,j=0;;) { if (aiuCanBuildShipType(alternativeShips->shipTypeNextPicks[i],(team->teamType == ScriptTeam))) { // found the ship we can build. Let's build them. numShipsToGet = numPointsLeftToGet / alternativeShips->shipNumEquivNextPicks[i]; if (numShipsToGet == 0) { numShipsToGet++; } //determine the number of ships that unit caps will let us build numShipsToBuild = aiuUnitCapCanBuildShip(aiCurrentAIPlayer, alternativeShips->shipTypeNextPicks[i], numShipsToGet); //if we can build all the ships if (numShipsToBuild == numShipsToGet) { aifTeamRequestsShipsCB(alternativeShips->shipTypeNextPicks[i],numShipsToGet,team,aivarLabelGet(doneVar), thisMove->params.fancyGetShips.priority); break; } //if we can only build a few else if (numShipsToBuild > numShipsToGet*0.25) { numPointsLeftToGet = (numShipsToGet - numShipsToBuild) * alternativeShips->shipNumEquivNextPicks[i]; dbgAssert(numPointsLeftToGet > 0); aifTeamRequestsShipsCB(alternativeShips->shipTypeNextPicks[i],numShipsToBuild,team,aivarLabelGet(doneVar), thisMove->params.fancyGetShips.priority); } } j++; if (j >= numAlternatives) { // aiplayerLog((aiIndex,"Warning - couldn't build any secondary ships")); goto buildbaseshiporfirst; } i++; if (i >= numAlternatives) { i = 0; } } } else { buildbaseshiporfirst: if (aiuCanBuildShipType(shiptype,(team->teamType == ScriptTeam))) { numShipsToGet = numPointsLeftToGet / ALTERNATIVE_SHIP_BASE; if (numShipsToGet == 0) { numShipsToGet++; } //determine the number of ships that unit caps will let us build numShipsToBuild = aiuUnitCapCanBuildShip(aiCurrentAIPlayer, shiptype, numShipsToGet); //if we can build all the ships if (numShipsToBuild == numShipsToGet) { aifTeamRequestsShipsCB(shiptype,numShipsToGet,team,aivarLabelGet(doneVar),thisMove->params.fancyGetShips.priority); } //if we can only build some else if (numShipsToBuild > numShipsToGet*0.75) { numPointsLeftToGet = (numShipsToBuild - numShipsToGet) * ALTERNATIVE_SHIP_BASE; aifTeamRequestsShipsCB(shiptype,numShipsToBuild,team,aivarLabelGet(doneVar),thisMove->params.fancyGetShips.priority); } else { aivarDestroy(doneVar); thisMove->params.fancyGetShips.doneVar = NULL; //postfinal: found that the fancygetships move gets stuck here, // even though the team already has all the ships, // added if and while loop // if the current team *already* has the ships we need, // the move is done if (team->shipList.selection->numShips) { if ((team->shipList.selection->ShipPtr[0]->shiptype == thisMove->params.fancyGetShips.shipType) && (team->shipList.selection->numShips >= thisMove->params.fancyGetShips.numShips)) { return TRUE; } // same as above, but goes through all the alternatives for (i=0;i<numAlternatives;i++) { if ((team->shipList.selection->ShipPtr[0]->shiptype == alternativeShips->shipTypeNextPicks[i]) && (team->shipList.selection->numShips >= (thisMove->params.fancyGetShips.numShips * 10)/alternativeShips->shipNumEquivNextPicks[i])) { return TRUE; } } } return FALSE; } } else { for (i=0;i<numAlternatives;i++) { if (aiuCanBuildShipType(alternativeShips->shipTypeNextPicks[i],(team->teamType == ScriptTeam))) { numShipsToGet = numPointsLeftToGet / alternativeShips->shipNumEquivNextPicks[i]; if (numShipsToGet == 0) { numShipsToGet++; } //determine the number of ships that unit caps will let us build numShipsToBuild = aiuUnitCapCanBuildShip(aiCurrentAIPlayer, alternativeShips->shipTypeNextPicks[i], numShipsToGet); //if we can build all the ships if (numShipsToBuild == numShipsToGet) { aifTeamRequestsShipsCB(alternativeShips->shipTypeNextPicks[i],numShipsToGet,team,aivarLabelGet(doneVar), thisMove->params.fancyGetShips.priority); goto havebuiltbaseshiporfirst; } //if we can only build some else if (numShipsToBuild > numShipsToGet*0.75) { numPointsLeftToGet = (numShipsToBuild - numShipsToGet) * ALTERNATIVE_SHIP_BASE; aifTeamRequestsShipsCB(alternativeShips->shipTypeNextPicks[i],numShipsToBuild,team,aivarLabelGet(doneVar), thisMove->params.fancyGetShips.priority); } } } // we couldn't build base ship, or any alternatives, // destroy the team and try again. aiplayerLog((aiIndex,"Warning - couldn't build base or secondary ship %i, deleting team", shiptype)); aivarDestroy(doneVar); thisMove->params.fancyGetShips.doneVar = NULL; bitSet(team->teamFlags, AIT_DestroyTeam); return TRUE; } havebuiltbaseshiporfirst:; } } else { aivarValueSet(doneVar, TRUE); } thisMove->processing = TRUE; } // normally in a move processing function, we'd check the // thisMove->wait flag, but... // // always wait for the ships to be built (we could loosen this a bit later, maybe) // but consider what happens when the rest of the ships are actually built if we // leave early // // Falko's note later: leaving early is too much trouble - formations become incomplete, // the ships built after the team executes a move sit around for // an undefined period of time and the current Numbers Low // event handler gets confused return aivarValueGet(thisMove->params.getShips.doneVar); }
/*----------------------------------------------------------------------------- Name : airResourceManager Description : Manages all the resources and non-combat ships for the computer player Inputs : orders - orders from the fleet manager Outputs : sets resource collectors to collect resources and optimizes resource controller and other non-combat ships Return : requests for new ships ----------------------------------------------------------------------------*/ void airResourceManager(void) { sdword cashGenerated; bool requestedSomething = FALSE, requestedResearch = FALSE; // Update continuously updated variables if (((aiCurrentAIPlayer->aiplayerFrameCount & UPDATE_RU_COUNT_RATE) == 0)|| (aiCurrentAIPlayer->airEasilyAccesibleRUsInWorld == -1)) { aiCurrentAIPlayer->airEasilyAccesibleRUsInWorld = NumberOfEasilyAccesibleRUs(aiCurrentAIPlayer->player); } cashGenerated = aiCurrentAIPlayer->player->resourceUnits + aiCurrentAIPlayer->NumRUsSpentOnAttman + aiCurrentAIPlayer->NumRUsSpentOnDefman + aiCurrentAIPlayer->NumRUsSpentOnScriptman; //determine if we should build any research ships if (singlePlayerGame || (!singlePlayerGame && bitTest(tpGameCreated.flag,MG_ResearchEnabled))) { if (aiuResourceFeatureEnabled(AIR_SMART_RESEARCH_SHIP_REQUESTS)) { if (airSmartResearchRequests(&requestedResearch)) { //a high priority request for a research ship has been entered return; } } else { if (airDumbResearchRequests(&requestedResearch)) { //a high priority request for a research ship has been entered return; } } } //determine if we should build any resource collectors if ((singlePlayerGame || (!singlePlayerGame && bitTest(tpGameCreated.flag,MG_HarvestinEnabled))) && (aiCurrentAIPlayer->airEasilyAccesibleRUsInWorld > MIN_WORTHWHILE_RUs)) { sdword totalRCollectors = aiCurrentAIPlayer->airNumRCollectors + aiCurrentAIPlayer->NumRCollectorsBeingBuilt; if (aiuResourceFeatureEnabled(AIR_SMART_COLLECTOR_REQUESTS)) { if (totalRCollectors < MAX_RCOLLECTORS_TO_BUILD) { if (totalRCollectors < aiCurrentAIPlayer->NumRUDockPoints*MAX_RCOLLECTORS_PER_DOCK_POINT) { if ((totalRCollectors == 0) || (aiCurrentAIPlayer->airEasilyAccesibleRUsInWorld > (totalRCollectors+1)*RUs_PER_RCOLLECTOR)) { // see if we have enough cash to make it worthwhile. (The more resource collectors we // already have, the more cash we want before building a new one because the Resource // Manager should always be providing an increasing amount of RU's). // Note that when we say cash, we mean cashGenerated if ((totalRCollectors == 0) || // if this is our first RCollector, we always want to build one (cashGenerated > BUILD_RC_CASH_TABLE_BASE + BUILD_RC_CASH_TABLE_INC * (totalRCollectors-1))) { if (totalRCollectors == 0) { if (aiuCanBuildShipType(ResourceCollector,FALSE)) { aifResourceManRequestsShipsCB(ResourceCollector, 1, REQUESTSHIPS_HIPRI); return; } } else { if (aiuCanBuildShipType(ResourceCollector,FALSE)) { aifResourceManRequestsShipsCB(ResourceCollector, 1, 0); requestedSomething = TRUE; } } } } } } } else { if (airDumbResourcerRequests()) { //a resource collector has been requested at high priority return; } } //determine if we should build any resource controllers if (aiuResourceFeatureEnabled(AIR_RESOURCE_CONTROLLER_REQUESTS) && (totalRCollectors >= MIN_RCOLLECTORS_FOR_CONTROLLER)) { sdword totalRControllers = aiCurrentAIPlayer->airNumRControllers + aiCurrentAIPlayer->NumRControllersBeingBuilt; if ((totalRControllers == 0) && (!requestedResearch)) { if (aiCurrentAIPlayer->airEasilyAccesibleRUsInWorld > (MIN_WORTHWHILE_RUs_FOR_CONTROLLER * universe.numPlayers)) { if (cashGenerated > BUILD_RCONTROLLER_CASH_BASE) { if (aiuCanBuildShipType(ResourceController,FALSE)) { aifResourceManRequestsShipsCB(ResourceController, 1, 0); return; } } } } } } if (!requestedSomething) { //determine if we should build any AdvanceSupportFrigates if (aiuResourceFeatureEnabled(AIR_SUPPORT_FRIGATE_REQUESTS) && ((!singlePlayerGame) && bitTest(tpGameCreated.flag, MG_FuelBurnEnabled)) ) { if (cashGenerated > BUILD_ASF_CASH_BASE) { sdword totalASF = aiCurrentAIPlayer->airNumASF + aiCurrentAIPlayer->NumASFBeingBuilt; if ((totalASF == 0) && aitNeedStrikeSupport(randyrandombetween(RANDOM_AI_PLAYER, 10, 15))) { if (aiuCanBuildShipType(AdvanceSupportFrigate,FALSE) && aiuUnitCapCanBuildShip(aiCurrentAIPlayer, AdvanceSupportFrigate, 1)) { aifResourceManRequestsShipsCB(AdvanceSupportFrigate, 1, 0); } } } } } if (aiCurrentAIPlayer->numSupportTeams) { airDivideSupportTasks(); } //Distress signals only work with active guard, //so that feature has to be activated as well if (aiuResourceFeatureEnabled(AIR_RESOURCE_DISTRESS_SIGNALS)) { airCheckForDistressSignals(); } }