/*============================================================================= Name : AIFleetMan Purpose : Controls construction of ships requested from combatman, defenseman, resourceman Created 5/28/1998 by gshaw Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include "types.h" #include "universe.h" #include "AIPlayer.h" #include "AIFleetMan.h" #include "AIResourceMan.h" #include "AIAttackMan.h" #include "AIDefenseMan.h" #include "AITeam.h" #include "AIUtilities.h" #include "AIVar.h" #include "CommandWrap.h" #include "select.h" #include "researchapi.h" #include "SinglePlayer.h" #include "MultiplayerGame.h" #include "alliance.h" #include "randy.h" Player *aifFindEnemyOf(Player *player) { uword i; Player *enemy; for (i=0;ifirstTurn = TRUE; aiplayer->recalculateAllies = TRUE; aiplayer->ResearchDelay = 0; aiplayer->ScriptCreator = aiplayer->player->PlayerMothership; aiplayer->AICreator = aiplayer->player->PlayerMothership; switch (aiplayer->aiplayerDifficultyLevel) { case AI_ADV: if (singlePlayerGame || ((!singlePlayerGame) && bitTest(tpGameCreated.flag, MG_Hyperspace))) { aiuEnableResourceFeature(AIF_HYPERSPACING); } case AI_INT: case AI_BEG: break; default: dbgAssert(FALSE); } } /*----------------------------------------------------------------------------- Name : airClose Description : Closes resource manager stuff in aiplayer Inputs : aiplayer Outputs : Return : ----------------------------------------------------------------------------*/ void aifClose(struct AIPlayer *aiplayer) { ; } /*----------------------------------------------------------------------------- Name : aifShipDied Description : Removes a dead ship from the Fleet Command's internal structures Inputs : aiplayer, ship - the ship that died Outputs : Return : TRUE if the ship was found and removed ----------------------------------------------------------------------------*/ bool aifShipDied(struct AIPlayer *aiplayer,ShipPtr ship) { bool return_value = FALSE; if (ship->playerowner == aiplayer->player && (ship->shiptype == Carrier || ship->shiptype == Mothership)) { RequestShips *request; Node *tempnode; //could be a creator ship if (ship == aiplayer->AICreator) { aiplayer->AICreator = NULL; return_value = TRUE; } else if (ship == aiplayer->ScriptCreator) { aiplayer->ScriptCreator = NULL; return_value = TRUE; } //now go through all the requests to make sure //this ship isn't referred to as a creator //check the resource requests if (aiplayer->ResourceManRequestShips.creator == ship) { aiplayer->ResourceManRequestShips.creator = NULL; return_value = TRUE; } //check the attack requests if (aiplayer->AttackManRequestShipsQ.head != NULL) { tempnode = aiplayer->AttackManRequestShipsQ.head; while (tempnode != NULL) { request = (RequestShips *)listGetStructOfNode(tempnode); if (request->creator == ship) { request->creator = NULL; return_value = TRUE; } tempnode = tempnode->next; } } //check the defense requests if (aiplayer->DefenseManRequestShipsQ.head != NULL) { tempnode = aiplayer->DefenseManRequestShipsQ.head; while (tempnode != NULL) { request = (RequestShips *)listGetStructOfNode(tempnode); if (request->creator == ship) { request->creator = NULL; return_value = TRUE; } tempnode = tempnode->next; } } //check the script requests if (aiplayer->ScriptManRequestShipsQ.head != NULL) { tempnode = aiplayer->ScriptManRequestShipsQ.head; while (tempnode != NULL) { request = (RequestShips *)listGetStructOfNode(tempnode); if (request->creator == ship) { request->creator = NULL; return_value = TRUE; } tempnode = tempnode->next; } } } return return_value; } void BuildShip(ShipStaticInfo *shipstatic,Player *player,sdword *incRUs,sdword *decRUs, ShipPtr creator) { #if(0) Node *shipnode; Ship *ship; sdword shipcount,classcount; CommandToDo *command; ShipStaticInfo *tempstat; #endif aiplayerLog((player->playerIndex,"Building ship %s; Total %i",ShipTypeToStr(shipstatic->shiptype),player->shiptotals[shipstatic->shiptype])); // unit caps checking code #if(0) shipnode = universe.ShipList.head; shipcount = 0; classcount = 0; while(shipnode != NULL) { ship = (Ship *)listGetStructOfNode(shipnode); if((ship->playerowner->playerIndex == player->playerIndex) && (!bitTest(ship->flags, SOF_Dead))) { if(ship->shiptype == shipstatic->shiptype) { shipcount++; } if(ship->staticinfo->shipclass == shipstatic->shipclass) { classcount++; } } shipnode = shipnode->next; } shipnode = universe.mainCommandLayer.todolist.head; while(shipnode != NULL) { command = (CommandToDo *)listGetStructOfNode(shipnode); if(command->ordertype.order == COMMAND_BUILDINGSHIP) { if(command->buildingship.playerIndex == player->playerIndex) { if(command->buildingship.shipType == shipstatic->shiptype) { shipcount++; } tempstat = GetShipStaticInfo(command->buildingship.shipType, player->race); if(tempstat->shipclass == shipstatic->shipclass) { classcount++; } } } shipnode = shipnode->next; } if((cdLimitCaps[shipstatic->shiptype] != -1) && (shipcount+1 > cdLimitCaps[shipstatic->shiptype])) { _asm nop; } if(classcount+1 > cdClassCaps[shipstatic->shipclass]) { _asm nop; } #endif if (shipstatic->shiptype == ResourceCollector) { aiCurrentAIPlayer->NumRCollectorsBeingBuilt++; } else if (shipstatic->shiptype == ResourceController) { aiCurrentAIPlayer->NumRControllersBeingBuilt++; } else if (shipstatic->shiptype == AdvanceSupportFrigate) { aiCurrentAIPlayer->NumASFBeingBuilt++; } else if (shipstatic->shiptype == ResearchShip) { aiCurrentAIPlayer->NumResearchShipsBeingBuilt++; } if (!creator) { creator = player->PlayerMothership; } clWrapBuildShip(&universe.mainCommandLayer, shipstatic->shiptype, creator->shiprace, player->playerIndex, creator); *incRUs += shipstatic->buildCost; *decRUs -= shipstatic->buildCost; } ShipStaticInfo *GetSubstituteShipStatic(ShipRace race) { ShipStaticInfo *shipstatic = NULL; switch (race) { case R1: case R2: shipstatic = GetShipStaticInfo(LightInterceptor,race); break; case P1: shipstatic = GetShipStaticInfo(P1Fighter,race); break; case P2: shipstatic = GetShipStaticInfo(P2Swarmer,race); break; default: dbgAssert(FALSE); } if (shipstatic) { if (!bitTest(shipstatic->staticheader.infoFlags, IF_InfoLoaded)) { shipstatic = NULL; } } return shipstatic; } /*----------------------------------------------------------------------------- Name : aifBuildRequestedShips Description : Decides which build request to process depending on which is more important - attack, defense, or resources Inputs : Outputs : Return : returns the chosen request ----------------------------------------------------------------------------*/ void aifBuildRequestedShips(RequestShips *scriptrequest,RequestShips *attrequest,RequestShips *defrequest,RequestShips *resourcerequest) { ShipStaticInfo *scriptshipstatic = NULL; sdword scriptnumships = 0; sdword scripttotalcost = 0; ShipStaticInfo *attshipstatic = NULL; sdword attnumships = 0; sdword atttotalcost = 0; ShipStaticInfo *defshipstatic = NULL; sdword defnumships = 0; sdword deftotalcost = 0; ShipStaticInfo *resourceshipstatic = NULL; sdword resourcenumships = 0; sdword resourcetotalcost = 0; Player *player = aiCurrentAIPlayer->player; Ship *playerMothership = player->PlayerMothership; sdword i; sdword RUsLeft = player->resourceUnits; ShipRace race; if (playerMothership == NULL) { return; // can't build anything, return } race = playerMothership->shiprace; if ((scriptrequest != NULL) && (scriptrequest->num_ships > 0)) { if ((RacesAllowedForGivenShip[scriptrequest->shiptype] & RaceToRaceBits(race))) { scriptshipstatic = GetShipStaticInfo(scriptrequest->shiptype,race); if (!bitTest(scriptshipstatic->staticheader.infoFlags, IF_InfoLoaded)) { scriptshipstatic = NULL; } } if (scriptshipstatic) { scriptnumships = (sdword)scriptrequest->num_ships; scripttotalcost = scriptnumships * scriptshipstatic->buildCost; } else { aiplayerLog((player->playerIndex,"Warning Script could not build shiprace %d shiptype %d",race,scriptrequest->shiptype)); scriptrequest->num_ships = -1; } } if ((attrequest != NULL) && (attrequest->num_ships > 0)) { if ((RacesAllowedForGivenShip[attrequest->shiptype] & RaceToRaceBits(race))) { attshipstatic = GetShipStaticInfo(attrequest->shiptype,race); if (!bitTest(attshipstatic->staticheader.infoFlags, IF_InfoLoaded)) { attshipstatic = NULL; } } if (attshipstatic) { attnumships = (sdword)attrequest->num_ships; atttotalcost = attnumships * attshipstatic->buildCost; } else { aiplayerLog((player->playerIndex,"Warning Attack could not build shiprace %d shiptype %d",race,attrequest->shiptype)); attrequest->num_ships = -1; } } if ((defrequest != NULL) && (defrequest->num_ships > 0)) { if ((RacesAllowedForGivenShip[defrequest->shiptype] & RaceToRaceBits(race))) { defshipstatic = GetShipStaticInfo(defrequest->shiptype,race); if (!bitTest(defshipstatic->staticheader.infoFlags, IF_InfoLoaded)) { defshipstatic = NULL; } } if (defshipstatic) { defnumships = (sdword)defrequest->num_ships; deftotalcost = defnumships * defshipstatic->buildCost; } else { aiplayerLog((player->playerIndex,"Warning Defense could not build shiprace %d shiptype %d",race,defrequest->shiptype)); defrequest->num_ships = -1; } } if ((resourcerequest != NULL) && (resourcerequest->num_ships > 0)) { if ((RacesAllowedForGivenShip[resourcerequest->shiptype] & RaceToRaceBits(race))) { resourceshipstatic = GetShipStaticInfo(resourcerequest->shiptype,race); if (!bitTest(resourceshipstatic->staticheader.infoFlags, IF_InfoLoaded)) { resourceshipstatic = NULL; } } if (resourceshipstatic) { resourcenumships = (sdword)resourcerequest->num_ships; resourcetotalcost = resourcenumships * resourceshipstatic->buildCost; } else { aiplayerLog((player->playerIndex,"Warning Resource could not build shiprace %d shiptype %d",race,resourcerequest->shiptype)); resourcerequest->num_ships = -1; } } if ((scripttotalcost + resourcetotalcost + atttotalcost + deftotalcost) <= RUsLeft) { // we can build everything, so let's do that // build everything resourceman wants for (i=0;iNumRUsSpentOnResourceman,&RUsLeft,resourcerequest->creator); } // build everything scriptman wants for (i=0;iNumRUsSpentOnScriptman,&RUsLeft,scriptrequest->creator); scriptrequest->num_ships--; } // build everything attman wants for (i=0;iNumRUsSpentOnAttman,&RUsLeft,attrequest->creator); attrequest->num_ships--; } // build everything defman wants for (i=0;iNumRUsSpentOnDefman,&RUsLeft,defrequest->creator); defrequest->num_ships--; } dbgAssert(RUsLeft >= 0); } else { // now choose who gets to go first, second, and third real32 totalRUsSpent = (real32) (aiCurrentAIPlayer->NumRUsSpentOnAttman + aiCurrentAIPlayer->NumRUsSpentOnDefman + aiCurrentAIPlayer->NumRUsSpentOnResourceman); real32 attmanbudgetratio = ((real32)aiCurrentAIPlayer->NumRUsSpentOnAttman) / totalRUsSpent; real32 defmanbudgetratio = ((real32)aiCurrentAIPlayer->NumRUsSpentOnDefman) / totalRUsSpent; real32 resourcemanbudgetratio = ((real32)aiCurrentAIPlayer->NumRUsSpentOnResourceman) / totalRUsSpent; real32 attmanbudgetoverflow = attmanbudgetratio / ATTMAN_BUILDPRIORITY_RATIO; real32 defmanbudgetoverflow = defmanbudgetratio / DEFMAN_BUILDPRIORITY_RATIO; real32 resourcemanbudgetoverflow = resourcemanbudgetratio / RESMAN_BUILDPRIORITY_RATIO; if ((resourcenumships) && (resourcerequest->priority & REQUESTSHIPS_HIPRI)) { resourcemanbudgetoverflow = -1.0f; } if ((attnumships) && (attrequest->priority & REQUESTSHIPS_HIPRI)) { attmanbudgetoverflow = -1.0f; } if ((defnumships) && (defrequest->priority & REQUESTSHIPS_HIPRI)) { defmanbudgetoverflow = -1.0f; } if (attnumships == 0) attmanbudgetoverflow = REALlyBig; if (defnumships == 0) defmanbudgetoverflow = REALlyBig; if (resourcenumships == 0) resourcemanbudgetoverflow = REALlyBig; //#define buildscriptships \ //#define buildattships \ //#define builddefships \ //#define buildresships \ if (scriptnumships) { for (i=0;(i= scriptshipstatic->buildCost);i++) \ { \ BuildShip(scriptshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnScriptman,&RUsLeft,scriptrequest->creator);\ scriptrequest->num_ships--; \ } // buildscriptships return; } if (attmanbudgetoverflow <= defmanbudgetoverflow) { // attackman goes before defenseman if (attmanbudgetoverflow <= resourcemanbudgetoverflow) { if (defmanbudgetoverflow <= resourcemanbudgetoverflow) { // buildattships for (i=0;(i= attshipstatic->buildCost);i++) \ { \ BuildShip(attshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnAttman,&RUsLeft,attrequest->creator); \ attrequest->num_ships--; \ } // builddefships // buildresships } else { // buildattships for (i=0;(i= attshipstatic->buildCost);i++) \ { \ BuildShip(attshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnAttman,&RUsLeft,attrequest->creator); \ attrequest->num_ships--; \ } // buildresships // builddefships } } else { for (i=0;(i= resourceshipstatic->buildCost);i++) \ { \ BuildShip(resourceshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnResourceman,&RUsLeft,resourcerequest->creator);\ } // buildresships // buildattships // builddefships } } else { // defenseman goes before attackman if (defmanbudgetoverflow <= resourcemanbudgetoverflow) { if (attmanbudgetoverflow <= resourcemanbudgetoverflow) { for (i=0;(i= defshipstatic->buildCost);i++) \ { \ BuildShip(defshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnDefman,&RUsLeft,defrequest->creator); \ defrequest->num_ships--; \ } // builddefships // buildattships // buildresships } else { for (i=0;(i= defshipstatic->buildCost);i++) \ { \ BuildShip(defshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnDefman,&RUsLeft,defrequest->creator); \ defrequest->num_ships--; \ } // builddefships // buildresships // buildattships } } else { for (i=0;(i= resourceshipstatic->buildCost);i++) \ { \ BuildShip(resourceshipstatic,player,&aiCurrentAIPlayer->NumRUsSpentOnResourceman,&RUsLeft,resourcerequest->creator);\ } // buildresships // builddefships // buildattships } } } return; } void aifAttackManRequestsShipsCB(ShipType shiptype,sdword number,sdword priority) { // add requests to Q RequestShips *requestShips = memAlloc(sizeof(RequestShips),"attackreqships",0); dbgAssert(number > 0); requestShips->shiptype = shiptype; requestShips->num_ships = number; requestShips->priority = priority; requestShips->creator = aiCurrentAIPlayer->AICreator; if (priority & REQUESTSHIPS_HIPRI) { listAddNodeBeginning(&aiCurrentAIPlayer->AttackManRequestShipsQ,&requestShips->node,requestShips); } else { listAddNode(&aiCurrentAIPlayer->AttackManRequestShipsQ,&requestShips->node,requestShips); } } void aifDefenseManRequestsShipsCB(ShipType shiptype,sdword number,sdword priority) { // add requests to Q RequestShips *requestShips = memAlloc(sizeof(RequestShips),"defreqships",0); dbgAssert(number > 0); requestShips->shiptype = shiptype; requestShips->num_ships = number; requestShips->priority = priority; requestShips->creator = aiCurrentAIPlayer->AICreator; if (priority & REQUESTSHIPS_HIPRI) { listAddNodeBeginning(&aiCurrentAIPlayer->DefenseManRequestShipsQ,&requestShips->node,requestShips); } else { listAddNode(&aiCurrentAIPlayer->DefenseManRequestShipsQ,&requestShips->node,requestShips); } } void aifScriptManRequestsShipsCB(ShipType shiptype,sdword number,sdword priority) { // add requests to Q RequestShips *requestShips = memAlloc(sizeof(RequestShips),"defreqships",0); dbgAssert(number > 0); requestShips->shiptype = shiptype; requestShips->num_ships = number; requestShips->priority = priority; requestShips->creator = aiCurrentAIPlayer->ScriptCreator; if (priority & REQUESTSHIPS_HIPRI) { listAddNodeBeginning(&aiCurrentAIPlayer->ScriptManRequestShipsQ,&requestShips->node,requestShips); } else { listAddNode(&aiCurrentAIPlayer->ScriptManRequestShipsQ,&requestShips->node,requestShips); } } void aifResourceManRequestsShipsCB(ShipType shiptype,sdword number,sdword priority) { dbgAssert(number > 0); aiCurrentAIPlayer->ResourceManRequestShips.shiptype = shiptype; aiCurrentAIPlayer->ResourceManRequestShips.num_ships = number; aiCurrentAIPlayer->ResourceManRequestShips.priority = priority; aiCurrentAIPlayer->ResourceManRequestShips.creator = aiCurrentAIPlayer->AICreator; } #define constructTeamWaiting(twaiting,stype,nships,tm,dSetVar) \ twaiting = memAlloc(sizeof(TeamWaitingForTheseShips),"teamwaitingships",0); \ twaiting##->shiptype = stype; \ twaiting##->num_ships = nships; \ twaiting##->team = tm; \ dbgAssert(strlen(dSetVar) <= AIVAR_LABEL_MAX_LENGTH); \ strcpy(twaiting##->doneSetVarStr,dSetVar) void aifTeamRequestsShipsCB(ShipType shiptype,sdword number,struct AITeam *team,char *doneSetVar, sdword priority) { TeamWaitingForTheseShips *teamWaiting; aiplayerLog((aiIndex, "%x Requesting %i %ss", team, number, ShipTypeToStr(shiptype))); switch (team->teamType) { case AttackTeam: // put request in Q under attackman aifAttackManRequestsShipsCB(shiptype,number,priority); // add to AttackManTeamWaitingForShipsQ constructTeamWaiting(teamWaiting,shiptype,number,team,doneSetVar); if (priority & REQUESTSHIPS_HIPRI) { listAddNodeBeginning(&aiCurrentAIPlayer->AttackManTeamsWaitingForShipsQ,&teamWaiting->node,teamWaiting); } else { listAddNode(&aiCurrentAIPlayer->AttackManTeamsWaitingForShipsQ,&teamWaiting->node,teamWaiting); } break; case DefenseTeam: // put request in Q under defenseman aifDefenseManRequestsShipsCB(shiptype,number,priority); // add to DefenseManTeamWaitingForShipsQ constructTeamWaiting(teamWaiting,shiptype,number,team,doneSetVar); if (priority & REQUESTSHIPS_HIPRI) { listAddNodeBeginning(&aiCurrentAIPlayer->DefenseManTeamsWaitingForShipsQ,&teamWaiting->node,teamWaiting); } else { listAddNode(&aiCurrentAIPlayer->DefenseManTeamsWaitingForShipsQ,&teamWaiting->node,teamWaiting); } break; case ScriptTeam: // put request in Q under scriptman aifScriptManRequestsShipsCB(shiptype,number,priority); // add to DefenseManTeamWaitingForShipsQ constructTeamWaiting(teamWaiting,shiptype,number,team,doneSetVar); if (priority & REQUESTSHIPS_HIPRI) { listAddNodeBeginning(&aiCurrentAIPlayer->ScriptManTeamsWaitingForShipsQ,&teamWaiting->node,teamWaiting); } else { listAddNode(&aiCurrentAIPlayer->ScriptManTeamsWaitingForShipsQ,&teamWaiting->node,teamWaiting); } break; case ResourceTeam: default: dbgAssert(FALSE); // not supported yet break; } } void RemoveTeamFromTeamWaitingQ(LinkedList *TeamWaitingQ,AITeam *team) { Node *node = TeamWaitingQ->head; Node *nextnode; TeamWaitingForTheseShips *teamWaiting; while (node != NULL) { teamWaiting = (TeamWaitingForTheseShips *)listGetStructOfNode(node); nextnode = node->next; if (teamWaiting->team == team) { listDeleteNode(node); } node = nextnode; } } void aifTeamDied(struct AIPlayer *aiplayer,struct AITeam *team, bool removeAllReferencesToTeam) { sdword i, j; MsgQueue *msgQP; RemoveTeamFromTeamWaitingQ(&aiplayer->AttackManTeamsWaitingForShipsQ,team); RemoveTeamFromTeamWaitingQ(&aiplayer->DefenseManTeamsWaitingForShipsQ,team); RemoveTeamFromTeamWaitingQ(&aiplayer->ScriptManTeamsWaitingForShipsQ,team); if (!removeAllReferencesToTeam) { //don't do anything else return; } // remove any messages from team that may still be queued up for (i = 0; i < aiCurrentAIPlayer->teamsUsed; ++i) { msgQP = aiCurrentAIPlayer->teams[i]->msgQueue; if (!msgQP) continue; for (j = 0; j < MSG_QUEUE_MAX_MSGS; ++j) if (msgQP->msgSenders[j] == team) { if (msgQP->msgs[j]) memFree(msgQP->msgs[j]); msgQP->msgs[j] = NULL; msgQP->msgSenders[j] = NULL; } } if (team->teamType == AttackTeam) { aiaTeamDied(aiplayer,team); } else if (team->teamType == DefenseTeam) { aidTeamDied(aiplayer,team); } else if (team->teamType == ResourceTeam) { airTeamDied(aiplayer,team); } } bool checkAddToTeam(LinkedList *TeamWaitingQ,Ship *ship) { Node *node = TeamWaitingQ->head; TeamWaitingForTheseShips *teamWaiting; while (node != NULL) { teamWaiting = (TeamWaitingForTheseShips *)listGetStructOfNode(node); dbgAssert(teamWaiting->num_ships > 0); if (teamWaiting->shiptype == ship->shiptype) { teamWaiting->num_ships--; aitAddShip(teamWaiting->team,ship); if (teamWaiting->num_ships == 0) { aivarValueSet(aivarFind(teamWaiting->doneSetVarStr),TRUE); listDeleteNode(node); } return TRUE; } node = node->next; } return FALSE; } /*----------------------------------------------------------------------------- Name : aifProcessShipBuildRequests Description : Goes through the attack, defense, resource and script ship build queues Inputs : Outputs : Return : void ----------------------------------------------------------------------------*/ void aifProcessShipBuildRequests(void) { RequestShips *attrequest = NULL,*defrequest = NULL,*resourcerequest = NULL,*scriptrequest = NULL, *temprequest = NULL; sdword olddefnumships; sdword oldattnumships; sdword oldscriptnumships; Player *player = aiCurrentAIPlayer->player; ubyte research_delay; Node *tempnode; udword tech; //amount of technology that needs to be researched if (aiCurrentAIPlayer->ResearchDelay) { research_delay = --aiCurrentAIPlayer->ResearchDelay; } else { research_delay = 0; aiCurrentAIPlayer->ResearchDelay = AIF_RESEARCH_DELAY[aiCurrentAIPlayer->aiplayerDifficultyLevel]; } aiCurrentAIPlayer->TechnologyDeficit = 0; if (aiCurrentAIPlayer->ResourceManRequestShips.num_ships > 0) { resourcerequest = &aiCurrentAIPlayer->ResourceManRequestShips; tech = rmTechRequiredForShip(player, resourcerequest->shiptype); if (tech) { aiCurrentAIPlayer->TechnologyDeficit += tech; if ((!research_delay) && (rmResearchTechForShip(player, resourcerequest->shiptype))) { aiplayerLog((player->playerIndex, "Researching %s for Resource", ShipTypeToStr(resourcerequest->shiptype))); } resourcerequest = NULL; } } if (aiCurrentAIPlayer->AttackManRequestShipsQ.head != NULL) { tempnode = aiCurrentAIPlayer->AttackManRequestShipsQ.head; attrequest = (RequestShips *)listGetStructOfNode(tempnode); tech = rmTechRequiredForShip(player, attrequest->shiptype); if (tech) { aiCurrentAIPlayer->TechnologyDeficit += tech; if ((!research_delay) && (rmResearchTechForShip(player, attrequest->shiptype))) aiplayerLog((player->playerIndex, "Researching %s for Offense", ShipTypeToStr(attrequest->shiptype))); //temporary attrequest = NULL; /* tempnode = tempnode->next; while (tempnode) { attrequest = (RequestShips *)listGetStructOfNode(tempnode); if ((attrequest) && (!rmTechRequiredForShip(player, attrequest->shiptype))) { break; } tempnode = tempnode->next; } if (!tempnode) { attrequest = NULL; } */ } if (attrequest) { oldattnumships = attrequest->num_ships; dbgAssert(oldattnumships > 0); } } if (aiCurrentAIPlayer->DefenseManRequestShipsQ.head != NULL) { tempnode = aiCurrentAIPlayer->DefenseManRequestShipsQ.head; defrequest = (RequestShips *)listGetStructOfNode(tempnode); tech = rmTechRequiredForShip(player, defrequest->shiptype); if (tech) { aiCurrentAIPlayer->TechnologyDeficit += tech; if ((!research_delay) && (rmResearchTechForShip(player, defrequest->shiptype))) aiplayerLog((player->playerIndex, "Researching %s for Defense", ShipTypeToStr(defrequest->shiptype))); //temporary defrequest = NULL; /* tempnode = tempnode->next; while (tempnode) { defrequest = (RequestShips *)listGetStructOfNode(tempnode); //go through list of defense requests to find something we can build //will this screw up priorities? if ((defrequest) && (!rmTechRequiredForShip(player, defrequest->shiptype))) { break; } tempnode = tempnode->next; } if (!tempnode) { defrequest = NULL; } */ } if (defrequest) { olddefnumships = defrequest->num_ships; dbgAssert(olddefnumships > 0); } } //it is assumed that any ship requested by the script is researched //therefore no research is done for the script system and no checking is done either if (aiCurrentAIPlayer->ScriptManRequestShipsQ.head != NULL) { scriptrequest = (RequestShips *)listGetStructOfNode(aiCurrentAIPlayer->ScriptManRequestShipsQ.head); oldscriptnumships = scriptrequest->num_ships; dbgAssert(oldscriptnumships > 0); } //go through the queues to find more stuff to research if needed if (rmFindFreeLab(player) != -1) { tempnode = aiCurrentAIPlayer->AttackManRequestShipsQ.head; while (tempnode != NULL) { temprequest = (RequestShips *)listGetStructOfNode(tempnode); if (rmTechRequiredForShip(player, temprequest->shiptype)) { if ((!research_delay) && (rmResearchTechForShip(player, temprequest->shiptype))) { aiplayerLog((player->playerIndex, "Researching %s later in Attack queue", ShipTypeToStr(temprequest->shiptype))); break; } } tempnode = tempnode->next; } } aifBuildRequestedShips(scriptrequest,attrequest,defrequest,resourcerequest); if (scriptrequest != NULL) { // check and see if we built any ships, and if we should remove from Q // dbgAssert(scriptrequest->num_ships >= 0); if (oldscriptnumships != scriptrequest->num_ships) { dbgAssert((oldscriptnumships - scriptrequest->num_ships) > 0); aiCurrentAIPlayer->ScriptManShipsBeingBuilt.NumShipsOfType[scriptrequest->shiptype] += (ubyte)(oldscriptnumships - scriptrequest->num_ships); } if (scriptrequest->num_ships <= 0) { // remove from Q listDeleteNode(&scriptrequest->node); } } if (attrequest != NULL) { // check and see if we built any ships, and if we should remove from Q // dbgAssert(attrequest->num_ships >= 0); if (oldattnumships != attrequest->num_ships) { dbgAssert((oldattnumships - attrequest->num_ships) > 0); aiCurrentAIPlayer->AttackManShipsBeingBuilt.NumShipsOfType[attrequest->shiptype] += (ubyte)(oldattnumships - attrequest->num_ships); } if (attrequest->num_ships <= 0) { // remove from Q listDeleteNode(&attrequest->node); } } if (defrequest != NULL) { // check and see if we built any ships, and if we should remove from Q // dbgAssert(defrequest->num_ships >= 0); if (olddefnumships != defrequest->num_ships) { dbgAssert((olddefnumships - defrequest->num_ships) > 0); aiCurrentAIPlayer->DefenseManShipsBeingBuilt.NumShipsOfType[defrequest->shiptype] += (ubyte)(olddefnumships - defrequest->num_ships); } if (defrequest->num_ships <= 0) { // remove from Q listDeleteNode(&defrequest->node); } } } /*----------------------------------------------------------------------------- Name : aifAssignNewShips Description : Checks who is requesting new ships and assigns them to the proper manager Inputs : Outputs : Return : void ----------------------------------------------------------------------------*/ void aifAssignNewShips(void) { GrowSelection *newships = &aiCurrentAIPlayer->newships; udword i; ShipPtr ship; for (i=0;iselection->numShips;) { ship = newships->selection->ShipPtr[i]; if ( (aiCurrentAIPlayer->ScriptManShipsBeingBuilt.NumShipsOfType[ship->shiptype] > 0) && checkAddToTeam(&aiCurrentAIPlayer->ScriptManTeamsWaitingForShipsQ,ship) ) { // script manager requested this ship to be built, so give it to scriptman. aiCurrentAIPlayer->ScriptManShipsBeingBuilt.NumShipsOfType[ship->shiptype]--; growSelectRemoveShip(newships,ship); continue; // check same index again because we removed a ship from selection we are scanning } else if ( (aiCurrentAIPlayer->AttackManShipsBeingBuilt.NumShipsOfType[ship->shiptype] > 0) && (checkAddToTeam(&aiCurrentAIPlayer->AttackManTeamsWaitingForShipsQ,ship)) ) { // attack manager requested this ship to be built, so give it to attackman. aiCurrentAIPlayer->AttackManShipsBeingBuilt.NumShipsOfType[ship->shiptype]--; growSelectRemoveShip(newships,ship); continue; // check same index again because we removed a ship from selection we are scanning } else if ( (aiCurrentAIPlayer->DefenseManShipsBeingBuilt.NumShipsOfType[ship->shiptype] > 0) && (checkAddToTeam(&aiCurrentAIPlayer->DefenseManTeamsWaitingForShipsQ,ship)) ) { // defense manager requested this ship to be built, so give it to defenseman. aiCurrentAIPlayer->DefenseManShipsBeingBuilt.NumShipsOfType[ship->shiptype]--; growSelectRemoveShip(newships,ship); continue; // check same index again because we removed a ship from selection we are scanning } else if ((ship->staticinfo->shipclass == CLASS_Resource) || (ship->staticinfo->shipclass == CLASS_NonCombat) || (ship->shiptype == ResourceController) || (ship->shiptype == AdvanceSupportFrigate) || (ship->shiptype == Mothership) || (ship->shiptype == Carrier)) { growSelectRemoveShip(newships,ship); airAddNewShip(ship); continue; // check same index again because we removed a ship from selection we are scanning } else { // leave in reserves } i++; } } /*============================================================================= Hyperspacing Logic Code: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aifHyperspaceInit Description : Initializes any hyperspacing stuff Inputs : aiplayer - the CPU to do hyperspacing initialization for Outputs : Whatever's needed to initialize hyperspacing Return : void ----------------------------------------------------------------------------*/ void aifHyperspaceInit(AIPlayer *aiplayer) { //determine what percentage of RUs to skim for hyperspacing //for now, just take off 8% aiplayer->aifHyperSkimming = 0.08f; } /*----------------------------------------------------------------------------- Name : aifSkimHyperspaceRUs Description : Banks RUs for Hyperspacing Inputs : none Outputs : transfers some new RUs to the aiplayer structure Return : void ----------------------------------------------------------------------------*/ void aifSkimHyperspaceRUs(void) { udword newResources, skimResources; Player *player = aiCurrentAIPlayer->player; if (aiCurrentAIPlayer->aifHyperSavings < 0) { // if the CPU is in debt, all new resources go to pay off the debt if (player->resourceUnits) { if (player->resourceUnits < (-(aiCurrentAIPlayer->aifHyperSavings))) { // the players resources do not exceed the debt. Pay off as much as possible aiplayerLog((aiIndex, "Paying off the debt. Savings = %i, deposit = %i", aiCurrentAIPlayer->aifHyperSavings, player->resourceUnits)); aiCurrentAIPlayer->aifHyperSavings += player->resourceUnits; player->resourceUnits = 0; } else { // the players resources exceed the debt. Pay off everything. aiplayerLog((aiIndex, "Paying off the entire debt.")); player->resourceUnits += aiCurrentAIPlayer->aifHyperSavings; aiCurrentAIPlayer->aifHyperSavings = 0; } } } else if (player->resourceUnits > aiCurrentAIPlayer->aifLastRUCount) { // if the CPU has acquired new resources, skim some off newResources = player->resourceUnits - aiCurrentAIPlayer->aifLastRUCount; skimResources = (udword)((real32)newResources * aiCurrentAIPlayer->aifHyperSkimming); aiCurrentAIPlayer->aifHyperSavings += skimResources; player->resourceUnits -= skimResources; aiplayerLog((aiIndex, "Skimming %i RUs for Hyperspacing. Savings = %i, RUs = %i", skimResources, aiCurrentAIPlayer->aifHyperSavings, player->resourceUnits)); } aiCurrentAIPlayer->aifLastRUCount = player->resourceUnits; } /*============================================================================= Ally Logic: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aifFindAllies Description : Looks at the other CPUs and allies with those that have the same primary enemy Inputs : Outputs : Sets up some alliances Return : void ----------------------------------------------------------------------------*/ extern udword AIPLAYER_BIGOTRY[]; void aifFindAllies(void) { udword i; AIPlayer *OtherCPU; udword HowMuchDoILoveMyFriends; HowMuchDoILoveMyFriends = randyrandom(RAN_AIPlayer, 100); for (i=0;iprimaryEnemyPlayer == aiCurrentAIPlayer->primaryEnemyPlayer) { // if their primary enemies are the same if ((HowMuchDoILoveMyFriends < AIPLAYER_BIGOTRY[i]) && !allianceArePlayersAllied(OtherCPU->player, aiCurrentAIPlayer->player)) { // if the CPU wants to be allied if they aren't allied //create an alliance clWrapSetAlliance(ALLIANCE_FORMNEWALLIANCE, OtherCPU->player->playerIndex, aiCurrentAIPlayer->player->playerIndex); } } else { // their primary enemies aren't the same if (allianceArePlayersAllied(OtherCPU->player, aiCurrentAIPlayer->player)) { // if they are already allied //break the alliance clWrapSetAlliance(ALLIANCE_BREAKALLIANCE, OtherCPU->player->playerIndex, aiCurrentAIPlayer->player->playerIndex); } } } } aiCurrentAIPlayer->recalculateAllies = FALSE; } /*============================================================================= Fleet Commands: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aifP2FleetCommand Description : Logic for fleet command for the P2 pirates Inputs : Outputs : Return : void ----------------------------------------------------------------------------*/ void aifP2FleetCommand(void) { Player *player = aiCurrentAIPlayer->player; aiuCreateBlobArrays(player); aiuUpdateKnowledgeOfEnemyShips(aiCurrentAIPlayer); aidClearDistressSignal(aiCurrentAIPlayer); aifAssignNewShips(); aiaP2AttackManager(); aitExecute(); aifProcessShipBuildRequests(); aiuDeleteBlobArrays(); } /*----------------------------------------------------------------------------- Name : aifFleetCommand Description : Logic for the top of the computer player command structure Inputs : aiplayer - the computer player structure Outputs : lotsa stuff Return : void ----------------------------------------------------------------------------*/ void aifFleetCommand(void) { Player *player = aiCurrentAIPlayer->player; bool hasFleetControl = (singlePlayerGame) ? singlePlayerGameInfo.giveComputerFleetControl : TRUE; aiIndex = aiCurrentAIPlayer->player->playerIndex; //temporary if (player->race == P2) { aifP2FleetCommand(); return; } if (aiCurrentAIPlayer->recalculateAllies) { aifFindAllies(); } aiuCreateBlobArrays(player); aiuUpdateKnowledgeOfEnemyShips(aiCurrentAIPlayer); aidClearDistressSignal(aiCurrentAIPlayer); aifAssignNewShips(); if (aiCurrentAIPlayer->firstTurn) { if (hasFleetControl) { aiaProcessSpecialTeams(); // airProcessSpecialTeams(); } aiCurrentAIPlayer->firstTurn = FALSE; } else { if (hasFleetControl) { if (aiuResourceFeatureEnabled(AIF_HYPERSPACING)) { aifSkimHyperspaceRUs(); } aiCurrentAIPlayer->ResourceManRequestShips.num_ships = 0; //call AttackMan - any ships requested will result in call to aifAttackManRequestsShipsCB aiaAttackManager(); //call DefenseMan - any ships requested will result in call to aifDefenseManRequestsShipsCB aidDefenseManager(); //call Resource Manager - any ships requested will result in call to aifResourceManRequestsShipsCB airResourceManager(); } } // call Team Manager - any ships requested will result in call to aifAttackManRequestsShipsCB or aifDefenseManRequestsShipsCB aitExecute(); aifProcessShipBuildRequests(); aiuDeleteBlobArrays(); }