#include "fastmath.h" #include "select.h" #include "AIUtilities.h" #include "AIHandler.h" #include "AIAttackMan.h" #include "dock.h" #include "SalCapCorvette.h" #include "singleplayer.h" #include "tutor.h" /*============================================================================= Special Move functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aimInsertMove Description : Inserts a new move into the team's movelist and sets the move as the team's current move Inputs : move - the move to add, team - the team to add it to Outputs : Return : void ----------------------------------------------------------------------------*/ void aimInsertMove(AITeam *team, struct AITeamMove *newMove) { if (team->curMove == NULL) { listAddNode(&(team->moves), &(newMove->listNode), newMove); listMoveNodeToHead(&(newMove->listNode)); team->curMove = (AITeamMove *)listGetStructOfNode(team->moves.head); } else { if ((team->curMove->type != MOVE_GETSHIPS) && (team->curMove->type != MOVE_FANCYGETSHIPS)) { team->curMove->processing = FALSE; } aitAddmoveBeforeAndMakeCurrent(team, newMove, team->curMove); } } /*============================================================================= Move Callback functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aimMoveSplitShipDied Description : Removes the reference to the dead ship, if there is one Inputs : team - split team, move - thismove, ship - the ship that died Outputs : Return : void ----------------------------------------------------------------------------*/ void aimMoveSplitShipDied(AITeam *team, AITeamMove *move, ShipPtr ship) { udword i; bool found = FALSE; if (move->params.movesplit.ships) { for (i=0;iparams.movesplit.ships->numShips;i++) { if (found == TRUE) { move->params.movesplit.destinations->point[i-1] = move->params.movesplit.destinations->point[i]; move->params.movesplit.ships->ShipPtr[i-1] = move->params.movesplit.ships->ShipPtr[i]; } if (ship == move->params.movesplit.ships->ShipPtr[i]) { found = TRUE; aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from move split")); } } if (found) { move->params.movesplit.ships->numShips--; aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from move split")); } } else { dbgAssert(FALSE); } } /*----------------------------------------------------------------------------- Name : aimMoveSplitClose Description : Deallocates the move split stuff Inputs : team, move Outputs : Deallocates the ships structure Return : void ----------------------------------------------------------------------------*/ void aimMoveSplitClose(AITeam *team, AITeamMove *move) { aiumemFree(move->params.movesplit.ships); aiumemFree(move->params.movesplit.destinations); aiplayerLog((team->aiplayerowner->player->playerIndex, "%x Closed Move Split Move", team)); } /*----------------------------------------------------------------------------- Name : aimInterceptShipDied Description : Checks to see if the ship that died is the ship being intercepted. Removes references if this is true Inputs : team - the team intercepting, move - the intercept move, ship - the ship that died Outputs : Return : void ----------------------------------------------------------------------------*/ void aimInterceptShipDied(AITeam *team, AITeamMove *move, ShipPtr ship) { if (ship == move->params.intercept.ship) { move->params.intercept.ship = NULL; } } /*----------------------------------------------------------------------------- Name : aimFlankAttackClose Description : Cleanly closes the Flank Attack move Inputs : team - the team the move belongs to move - the move to close Outputs : Deallocates the targets structure Return : void ----------------------------------------------------------------------------*/ void aimFlankAttackClose(AITeam *team, struct AITeamMove *move) { aiumemFree(move->params.flankatt.targets); aiplayerLog((team->aiplayerowner->player->playerIndex,"%x Closed Flank Attack Move", team)); } /*----------------------------------------------------------------------------- Name : aimFlankAttackShipDied Description : Deals with a ship dying while a team is has a flanking attack in its move list Inputs : team - the team with the flanking attack move move - the flanking attack move ship - the ship that died Outputs : Removes the ship from any structure it might be a part of Return : void ----------------------------------------------------------------------------*/ void aimFlankAttackShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if (move->params.flankatt.targets != NULL) { if (clRemoveShipFromSelection(move->params.advatt.targets, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from Flanking Attack Target")); } } } /*----------------------------------------------------------------------------- Name : aimAdvancedAttackClose Description : Cleanly closes the advanced attack move Inputs : team - the team the move belongs to, move - the move to close Outputs : Deallocates the targets structure Return : void ----------------------------------------------------------------------------*/ void aimAdvancedAttackClose(AITeam *team, struct AITeamMove *move) { aiumemFree(move->params.advatt.targets); aiplayerLog((team->aiplayerowner->player->playerIndex,"%x Closed Advanced Attack Move", team)); } /*----------------------------------------------------------------------------- Name : aimAdvancedAttackShipDied Description : Deals with a ship dying while a team is performing an advanced attack. The target selection and target_ship pointer need to be checked to see if the dead ship is part of that selection Inputs : team - the attacking team move - the advanced attack move ship - the dead ship Outputs : Removes the ship from any structure it might be a part of Return : void ----------------------------------------------------------------------------*/ void aimAdvancedAttackShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if (move->params.advatt.targets != NULL) { if (clRemoveShipFromSelection(move->params.advatt.targets, ship)) { // postfinal: below commented out to try reissuing the attack after a target dies // if (move->params.advatt.target_ship == ship) // { // move->params.advatt.target_ship = NULL; // move->processing = FALSE; if (team->curMove == move) { move->processing = FALSE; // aimProcessAdvancedAttack(team) } // } aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from Advanced Attack Target")); } } } /*----------------------------------------------------------------------------- Name : aimMoveAttackShipDied Description : Ship dying while a move attack is happening Inputs : team, move, ship Outputs : removes ship from structure Return : void ----------------------------------------------------------------------------*/ void aimMoveAttackShipDied(AITeam *team, struct AITeamMove *move, ShipPtr ship) { if (move->params.moveatt.targets != NULL) { if (clRemoveShipFromSelection(move->params.moveatt.targets, ship)) { if (move->params.moveatt.target_ship == ship) { move->params.moveatt.target_ship = NULL; } aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from MoveAttack move")); } } } /*----------------------------------------------------------------------------- Name : aimMoveAttackClose Description : Closes the move attack move Inputs : team, move Outputs : deallocates the targets structure Return : void ----------------------------------------------------------------------------*/ void aimMoveAttackClose(AITeam *team, struct AITeamMove *move) { aiumemFree(move->params.moveatt.targets); aiplayerLog((team->aiplayerowner->player->playerIndex,"%x Closed Move Attack Move", team)); } /*----------------------------------------------------------------------------- Name : aimHarassAttackShipDied Description : Deals with a ship dying while a team is doing a harass attack - if the ship that died is the ship the team was harassing, the reference to that ship is removed Inputs : team - the harassing team move - the harass move ship - the ship that died Outputs : Return : void ----------------------------------------------------------------------------*/ void aimHarassAttackShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if ((move->params.harass.target != NULL) && (move->params.harass.target == ship)) { //removes the target ship from the structure move->params.harass.target = NULL; if (move->events.firing.triggered) { move->events.firing.triggered = FALSE; if (team->shipList.selection->numShips) { aiuWrapFormation(team->shipList.selection,DELTA3D_FORMATION); } } //if the ship was being harassed, it is removed if (move->processing) { move->processing = FALSE; } aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from harass target")); } } /*----------------------------------------------------------------------------- Name : aimDockClose Description : Cleanly closes the dock move Inputs : team - the team the move belongs to move - the move to close Outputs : Deallocates the shipsDocking structure Return : void ----------------------------------------------------------------------------*/ void aimDockClose(AITeam *team, struct AITeamMove *move) { aiumemFree(move->params.dock.shipsDocking); move->params.dock.shipsDocking = NULL; move->params.dock.dockAt = NULL; } /*----------------------------------------------------------------------------- Name : aimDockShipDied Description : Deals with a ship dying while a team is doing a dock command Inputs : team - the docking team move - the dock move ship - the ship that died Outputs : removes references of the ship from the dock structure Return : void ----------------------------------------------------------------------------*/ void aimDockShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if (move->params.dock.shipsDocking != NULL) { if (clRemoveShipFromSelection(move->params.dock.shipsDocking, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from dock structure")); } } if (move->params.dock.dockAt == ship) { move->params.dock.dockAt = NULL; aiplayerLog((team->aiplayerowner->player->playerIndex,"Cleared dockAt Ship from dock structure")); } } /*----------------------------------------------------------------------------- Name : aimDefendMothershipClose Description : Cleanly closes the defend mothership move Inputs : team - the team defending the mothership, move - the move to close Outputs : Deallocates the defend mothership structure Return : void ----------------------------------------------------------------------------*/ void aimDefendMothershipClose(AITeam *team, struct AITeamMove *move) { //blah blah blah } /*----------------------------------------------------------------------------- Name : aimDefendMothershipShipDied Description : Deals with a ship dying while a team is defending the mothership Inputs : team - the team defending the mothership move - the defend mothership move ship - the ship that died Outputs : removes references of the ship from the move structure Return : void ----------------------------------------------------------------------------*/ void aimDefendMothershipShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if ((move->params.defmoship.targets) && (clRemoveShipFromSelection(move->params.defmoship.targets, ship))) { memFree(move->params.defmoship.targets); move->params.defmoship.targets = NULL; aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from defend mothership structure")); move->processing = FALSE; aimProcessDefendMothership(team); } } /*----------------------------------------------------------------------------- Name : aimPatrolMoveClose Description : Deallocates the path structure Inputs : team - the team that is executing the move, move - the move Outputs : deallocates the path structure in the patrol move Return : void ----------------------------------------------------------------------------*/ void aimPatrolMoveClose(AITeam *team, struct AITeamMove *move) { memFree(move->params.patrolmove.path); } /*----------------------------------------------------------------------------- Name : aimSupportShipDied Description : Deals with a ship dying while a team is supporting a set of ships Inputs : team - the team doing the supporting, move - the support move, ship - the ship that died Outputs : removes references of the ship from the move structure Return : void ----------------------------------------------------------------------------*/ void aimSupportShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if ((move->params.support.ships) && (clRemoveShipFromSelection(move->params.support.ships, ship))) { aiplayerLog((team->aiplayerowner->player->playerIndex,"Removed Ship from Support move structure")); } } /*----------------------------------------------------------------------------- Name : aimSupportClose Description : Deallocates the ships structure in the support move Inputs : team - the team that is executing the move, move - the move being executed Outputs : Deallocates a selection Return : void ----------------------------------------------------------------------------*/ void aimSupportClose(AITeam *team, struct AITeamMove *move) { aiumemFree(move->params.support.ships); } /*----------------------------------------------------------------------------- Name : aimShipReconShipDied Description : Deals with a ship dying while a team is doing a ship reconaissance Inputs : team - the team doing the reconaissance, move - the ship recon move, ship - the ship that died Outputs : removes references of the ship from the move structure Return : void ----------------------------------------------------------------------------*/ void aimShipReconShipDied(AITeam *team, struct AITeamMove *move, Ship *ship) { if (clRemoveShipFromSelection(move->params.shiprecon.ships, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from ReconShip ships")); } if ((move->params.shiprecon.foundships) && (clRemoveShipFromSelection(move->params.shiprecon.foundships, ship))) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from ReconShips shipsfound")); if (!move->params.shiprecon.foundships->numShips) { memFree(move->params.shiprecon.foundships); move->params.shiprecon.foundships = NULL; } } } /*----------------------------------------------------------------------------- Name : aimShipReconClose Description : Closes the shiprecon move Inputs : move - the shiprecon move Outputs : deallocs a few structures Return : void ----------------------------------------------------------------------------*/ void aimShipReconClose(AITeam *team, struct AITeamMove *move) { aiumemFree(move->params.shiprecon.foundships); aiumemFree(move->params.shiprecon.ships); } /*----------------------------------------------------------------------------- Name : aimControlResourcesShipDied Description : Inputs : Outputs : Return : void ----------------------------------------------------------------------------*/ void aimControlResourcesShipDied(AITeam *team, struct AITeamMove *move, ShipPtr ship) { //already taken care of because the ships pointer points to //aiplayer->airResourceCollectors, which removes ships on its own } /*----------------------------------------------------------------------------- Name : aimSwarmAttackShipDied Description : Deals with a ship dying while a swarm attack is happening Inputs : team, move ship Outputs : removes the ship from one of the swarm attack structures Return : void ----------------------------------------------------------------------------*/ void aimSwarmAttackShipDied(AITeam *team, struct AITeamMove *move, ShipPtr ship) { SelectCommand *targets = move->params.swarmatt.targets; SelectCommand *othertargets = move->params.swarmatt.othertargets; SelectCommand *teamShips = team->shipList.selection; if (growSelectRemoveShip(&move->params.swarmatt.newSwarmers, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from swarm attack new swarmers")); return; } if ((othertargets) && clRemoveShipFromSelection(othertargets, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from swarm attack othertargets")); if (!othertargets->numShips) { aiumemFree(move->params.swarmatt.othertargets); } } if ((targets) && (clRemoveShipFromSelection(targets, ship))) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from swarm attack targets")); if (!targets->numShips) { // aiumemFree(move->params.swarmatt.targets); // targets = move->params.swarmatt.targets = aiuFindNearbyEnemyShips(ship, 1000); // if (!targets->numShips) // { aiumemFree(move->params.swarmatt.targets); return; // } } if (teamShips->numShips) { //give attack command to all swarmers if ((teamShips->numShips > 2*targets->numShips) && ((isShipOfClass(targets->ShipPtr[0], CLASS_Corvette)) || (isShipOfClass(targets->ShipPtr[0], CLASS_Fighter)))) { //split them if possible aiuSplitAttack(teamShips, targets); } else { //group attack otherwise aiuWrapAttack(teamShips, targets); } } return; } } /*----------------------------------------------------------------------------- Name : aimSwarmAttackClose Description : Closes swarm attack move Inputs : team, move Outputs : frees a few structures Return : void ----------------------------------------------------------------------------*/ void aimSwarmAttackClose(AITeam *team, AITeamMove *move) { growSelectClose(&move->params.swarmatt.newSwarmers); aiumemFree(move->params.swarmatt.targets); aiumemFree(move->params.swarmatt.othertargets); } /*----------------------------------------------------------------------------- Name : aimSwarmDefenseShipDied Description : Deals with a ship dying while a swarm defense is happening Inputs : team, move ship Outputs : removes the ship from one of the swarm defense structures Return : void ----------------------------------------------------------------------------*/ void aimSwarmDefenseShipDied(AITeam *team, struct AITeamMove *move, ShipPtr ship) { if (growSelectRemoveShip(&move->params.swarmdef.newSwarmers, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from swarm defense new swarmers")); return; } if (move->params.swarmdef.guarding) { if (ship == move->params.swarmdef.guarding->ShipPtr[0]) { bitClear(team->teamFlags, TEAM_AmIBeingWatched); } if (clRemoveShipFromSelection(move->params.swarmdef.guarding, ship)) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Removed Ship from swarm defense guarding")); return; } } if ((move->params.swarmdef.Pods) && (clRemoveShipFromSelection(move->params.swarmdef.Pods, ship))) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Swarmer Pod killed")); } } /*----------------------------------------------------------------------------- Name : aimSwarmDefenseClose Description : Closes swarm defense move Inputs : team, move Outputs : frees a few structures Return : void ----------------------------------------------------------------------------*/ void aimSwarmDefenseClose(AITeam *team, AITeamMove *move) { growSelectClose(&move->params.swarmdef.newSwarmers); aiumemFree(move->params.swarmdef.guarding); aiumemFree(move->params.swarmdef.Pods); } /*----------------------------------------------------------------------------- Name : aimResourceVolumeResourceDied Description : Deals with a resource dying while the resource volume move exists Inputs : team - the team doing the resourcing, move - the resource volume move, resource - the resource that died Outputs : Return : void ----------------------------------------------------------------------------*/ void aimResourceVolumeResourceDied(AITeam *team, AITeamMove *move, Resource *resource) { udword i; if ((move->params.resvolume.volResources) && (clRemoveTargetFromSelection((SelectAnyCommand *)move->params.resvolume.volResources, (TargetPtr)resource))) { // aiplayerLog((team->aiplayerowner->player->playerIndex, "Resource removed from volResources")); if (!move->params.resvolume.volResources->numResources) { aiumemFree(move->params.resvolume.volResources); } } if ((move->params.resvolume.takenResources) && (clRemoveTargetFromSelection((SelectAnyCommand *)move->params.resvolume.takenResources, (TargetPtr)resource))) { aiplayerLog((team->aiplayerowner->player->playerIndex, "Resource removed from takenResources")); // if (!move->params.resvolume.takenResources->numResources) // { // aiumemFree(move->params.resvolume.takenResources); // } } if (move->params.resvolume.strictVolume) { for (i=0;ishipList.selection->numShips;i++) { if (bitTest(team->shipList.selection->ShipPtr[i]->specialFlags, SPECIAL_Finished_Resource)) { SelectCommand selone; selone.numShips = 1; selone.ShipPtr[0] = team->shipList.selection->ShipPtr[i]; bitClear(selone.ShipPtr[0]->specialFlags, SPECIAL_Finished_Resource); aiuWrapHalt(&selone); } } } } /*----------------------------------------------------------------------------- Name : aimResourceVolumeShipDied Description : If a resource collector dies, the resources of that volume need to be recalculated Inputs : team, move, ship Outputs : Deallocates some structures Return : void ----------------------------------------------------------------------------*/ void aimResourceVolumeShipDied(AITeam *team, AITeamMove *move, ShipPtr ship) { if (ShipInSelection(team->shipList.selection, ship)) { aiumemFree(move->params.resvolume.volResources); } } /*----------------------------------------------------------------------------- Name : aimResourceVolumeClose Description : Deallocates the resource volume structures Inputs : team, move Outputs : Deallocates some structures Return : void ----------------------------------------------------------------------------*/ void aimResourceVolumeClose(AITeam *team, AITeamMove *move) { aiumemFree(move->params.resvolume.volResources); aiumemFree(move->params.resvolume.takenResources); } /*----------------------------------------------------------------------------- Name : aimCaptureShipDied Description : Deals with a ship dying while the capture move is being executed Inputs : team, move, ship Outputs : Deallocates some pointers Return : void ----------------------------------------------------------------------------*/ void aimCaptureShipDied(AITeam *team, AITeamMove *move, ShipPtr ship) { if (ship == move->params.capture.ship) { move->params.capture.ship = NULL; aiplayerLog((aiIndex, "Captured ship died")); } } /*----------------------------------------------------------------------------- Name : aimMothershipMoveShipDied Description : If a mothership dies, a new one must be found. If there isn't one, we lost anyway, so there's no point Inputs : team, move, ship Outputs : Return : void ----------------------------------------------------------------------------*/ void aimMothershipMoveShipDied(AITeam *team, AITeamMove *move, ShipPtr ship) { //do something here... make sure it's really cool. } /*============================================================================= Move Processing Functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aimProcessMove Description : Moves the team if it isn't moving yet, detects when the team is done moving Inputs : team - the team doing the moving Outputs : Return : Returns true when the team is done moving ----------------------------------------------------------------------------*/ sdword aimProcessMove(AITeam *team) { AITeamMove *thisMove = team->curMove; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Move Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { //give command layer move command if (aiuWrapMove(team->shipList.selection, thisMove->params.move.destination)) { thisMove->processing = TRUE; } else { aiplayerLog((aiIndex, "Can't Move!!!")); return FALSE; } } else { if (aitTeamIsFinishedMoving(team, thisMove->params.move.destination, AIM_DIST_MOVE_END)) { // aiplayerLog((aiIndex,"Moving team reached destination")); return TRUE; } } if (thisMove->wait) { return FALSE; } else { return TRUE; } } /*----------------------------------------------------------------------------- Name : aimProcessMoveSplit Description : Moves each ship to their corresponding destination Inputs : team - the team that is splitting Outputs : Moves ships around Return : Returns TRUE when the team is done moving ----------------------------------------------------------------------------*/ sdword aimProcessMoveSplit(AITeam *team) { AITeamMove *thisMove = team->curMove; SelectCommand selone; udword i; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex, "Move Split Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { selone.numShips = 1; for (i=0;iparams.movesplit.ships->numShips;i++) { selone.ShipPtr[0] = thisMove->params.movesplit.ships->ShipPtr[i]; aiuWrapMove(&selone, thisMove->params.movesplit.destinations->point[i]); } thisMove->processing = TRUE; } else { for (i=0;iparams.movesplit.ships->numShips;i++) { if (!vecIsZero(thisMove->params.movesplit.ships->ShipPtr[i]->moveTo)) { return FALSE; } } return TRUE; } if (thisMove->wait) { return FALSE; } else { return TRUE; } } /*----------------------------------------------------------------------------- Name : aimProcessHyperspace Description : Hyperspaces the team to a certain destination Inputs : team - the team that's hyperspacing Outputs : See "description" Return : Returns TRUE when the team is done hyperspacing ----------------------------------------------------------------------------*/ sdword aimProcessHyperspace(AITeam *team) { AITeamMove *thisMove = team->curMove; MaxSelection hyperspacingShips; real32 cost, avg_size; vector current_location; udword i; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex, "Hyperspace Move, Zero Sized Team")); return TRUE; } hyperspacingShips.numShips = 0; if (!thisMove->processing) { aiuFilterSelectableShips(team->shipList.selection,&hyperspacingShips); makeSelectionHyperspaceCapable((SelectCommand *)&hyperspacingShips); if (hyperspacingShips.numShips) { current_location = selCentrePointComputeGeneral((MaxSelection *)&hyperspacingShips, &avg_size); cost = hyperspaceCost(fsqrt(aiuFindDistanceSquared(current_location, thisMove->params.move.destination)), (SelectCommand *)&hyperspacingShips); aiCurrentAIPlayer->aifHyperSavings -= (sdword)cost; clWrapMpHyperspace(&universe.mainCommandLayer, (SelectCommand *)&hyperspacingShips, current_location, thisMove->params.move.destination); aiplayerLog((aiIndex, "%x Hyperspacing NOW! Cost = %i Savings = %i", team, (sdword)cost, aiCurrentAIPlayer->aifHyperSavings)); } thisMove->processing = TRUE; return FALSE; } else { for (i=0;ishipList.selection->numShips;i++) { if (!bitTest(team->shipList.selection->ShipPtr[0]->flags, SOF_Selectable)) { return FALSE; } } return TRUE; } } /*----------------------------------------------------------------------------- Name : aimProcessIntercept Description : Checks the ship to see if it's moving, if it is, calculate an intercept point, create a move to it's location Inputs : team - the intercepting team Outputs : May create some moveteam moves Return : TRUE if the move is finished ----------------------------------------------------------------------------*/ sdword aimProcessIntercept(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; ShipPtr ship = thisMove->params.intercept.ship; if (ship == NULL) { return TRUE; } if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Intercept Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { if (!vecIsZero(ship->moveTo)) { //make destination halfway point between target ship and it's destination //later add code to deal with when the intercepting team is directly // in the path of the ship it's intercepting vecAdd(thisMove->params.intercept.destination, ship->moveTo, ship->posinfo.position); vecMultiplyByScalar(thisMove->params.intercept.destination, 0.5); thisMove->params.intercept.moving = TRUE; } else { thisMove->params.intercept.destination = ship->posinfo.position; thisMove->params.intercept.moving = FALSE; } newMove = aimCreateMoveTeamNoAdd(team, thisMove->params.intercept.destination, thisMove->formation, /*thisMove->tactics,*/ FALSE, TRUE); newMove->events = thisMove->events; thisMove->processing = TRUE; thisMove->params.intercept.next_int = universe.totaltimeelapsed + thisMove->params.intercept.interval; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } else { //if the team has arrived if (aiuFindDistanceSquared(ship->posinfo.position, team->shipList.selection->ShipPtr[0]->posinfo.position) < AIM_INTERCEPT_FINISH_DISTSQ) { return TRUE; } //only do checks during certain intervals if (thisMove->params.intercept.next_int > universe.totaltimeelapsed) { return FALSE; } //if the intercept target has started moving or changed course, recalculate destination if ((!thisMove->params.intercept.moving) && (aiuFindDistanceSquared(ship->posinfo.position, thisMove->params.intercept.destination) > AIM_INTERCEPT_RECALC_DISTSQ)) { thisMove->processing = FALSE; } else if ((thisMove->params.intercept.moving) && (!vecAreEqual(ship->moveTo, thisMove->params.intercept.destination))) { thisMove->processing = FALSE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessMoveTo Description : Moves a team for the amount of time or distance specified in limiter Inputs : team - the team that's going to move Outputs : Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessMoveTo(AITeam *team) { AITeamMove *thisMove = team->curMove; vector current_location; real32 avg_size; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Move To Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { if (!aiuShipsAreHidden(team->shipList.selection)) { //give command layer move command aiuWrapMove(team->shipList.selection, thisMove->params.moveTo.destination); thisMove->params.moveTo.timer = universe.totaltimeelapsed; thisMove->params.moveTo.source = selCentrePointComputeGeneral((MaxSelection *)team->shipList.selection, &avg_size); thisMove->processing = TRUE; } } else { switch (thisMove->params.moveTo.type) { case TIME_LIMITED: if (universe.totaltimeelapsed - thisMove->params.moveTo.timer > thisMove->params.moveTo.limiter) { aiuWrapHalt(team->shipList.selection); // aiplayerLog((aiIndex,"Move To team reached timed destination")); return TRUE; } break; case DISTANCE_LIMITED: current_location = selCentrePointComputeGeneral((MaxSelection *)team->shipList.selection, &avg_size); if (fsqrt(aiuFindDistanceSquared(current_location, thisMove->params.moveTo.source)) > thisMove->params.moveTo.limiter) { aiuWrapHalt(team->shipList.selection); // aiplayerLog((aiIndex,"Move To team reached distance destination")); return TRUE; } break; default: aiplayerLog((aiIndex,"Unknown Move To type")); } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessCountShips Description : Counts ships within visual range of the team Inputs : team - the team doing the counting Outputs : Return : Returns TRUE when the team is done counting ----------------------------------------------------------------------------*/ sdword aimProcessCountShips(AITeam *team) { //just a placeholder for now //later maybe actually count ships nearby aiplayerLog((aiIndex,"Counting Ships... 1, 2, 3, 4...")); return TRUE; } /*----------------------------------------------------------------------------- Name : aimProcessFlankAttack Description : Moves the ship to the flanking position, then issues an attack order Inputs : team - the team doing the attacking Outputs : A neato flanking attack Return : Returns TRUE when the team is done attacking ----------------------------------------------------------------------------*/ sdword aimProcessFlankAttack(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; vector current_location, target_location, flank_location, zerovec = {0,0,0}; real32 avg_size; if (team->shipList.selection->numShips == 0) { //no ships to do anything with, finish move aiplayerLog((aiIndex,"Flank Attack Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { current_location = selCentrePointComputeGeneral((MaxSelection *)team->shipList.selection, &avg_size); target_location = selCentrePointComputeGeneral((MaxSelection *)thisMove->params.flankatt.targets, &avg_size); //find the flanking coordinates flank_location = aiuGenerateFlankCoordinates(target_location, current_location, zerovec, AIM_FLANK_ATTACK_RADIUS); if (thisMove->params.flankatt.hyperspace) { //create a move to hyperspace to those coordinates (with a wait) newMove = aimCreateHyperspaceNoAdd(team, flank_location, AIM_FLANK_MOVE_FORMATION, TRUE, TRUE); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } else { //create a move to move to those coordinates (with a wait) newMove = aimCreateMoveTeamNoAdd(team, flank_location, AIM_FLANK_MOVE_FORMATION, TRUE, TRUE); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } //create an attack move to target ships //previously normal attack later change to general attack newMove = aimCreateAdvancedAttackNoAdd(team, selectMemDupSelection(thisMove->params.flankatt.targets, "dupfla", 0), AIM_FLANK_ATTACK_FORMATION,Aggressive, TRUE, TRUE); listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); //remove shipdied and close callbacks //the attack move will take care of these // thisMove->moveShipDiedFunction = NULL; // thisMove->moveCloseFunction = NULL; //leave this function thisMove->processing = TRUE; return FALSE; } return TRUE; } /*----------------------------------------------------------------------------- Name : aimProcessMoveAttack Description : Gives the attack command then if in range and not moving, find a random flank point and move to it Inputs : team Outputs : Creates some new move Return : TRUE when all the targets are dead ----------------------------------------------------------------------------*/ sdword aimProcessMoveAttack(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; SelectCommand *victims = thisMove->params.moveatt.targets, *teamShips = team->shipList.selection; vector victims_center, teams_center, destination, origin = {0,0,0}; real32 dummy,mingunrangesq; if (teamShips->numShips == 0) { //team is dead aiplayerLog((aiIndex,"Move Attack Move, Zero size team")); return TRUE; } if ((victims == NULL) || (victims->numShips == 0)) { //we're done return TRUE; } if (!thisMove->processing) { newMove = aimCreateAttackNoAdd(team, selectMemDupSelection(victims, "moveatt", 0), thisMove->formation, FALSE, TRUE); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); thisMove->processing = TRUE; return FALSE; } else { if ((!team->shipList.selection->ShipPtr[0]->command) || (team->shipList.selection->ShipPtr[0]->command->ordertype.order != COMMAND_ATTACK)) { //somehow the attack command has been lost //reissue the attack command newMove = aimCreateAttackNoAdd(team, selectMemDupSelection(victims, "moveatt2",0), thisMove->formation, FALSE, TRUE); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); vecZeroVector(thisMove->params.moveatt.destination); return FALSE; } else if ((vecIsZero(thisMove->params.moveatt.destination) && aiuShipsInGunRangeOfTargets(team->shipList.selection)) || (!vecIsZero(thisMove->params.moveatt.destination) && vecIsZero(teamShips->ShipPtr[0]->moveTo)) || (aiuFindDistanceSquared(selCentrePointComputeGeneral((MaxSelection *)team->shipList.selection, &dummy), thisMove->params.moveatt.destination) < 10000)) //10000 == range squared //if the team is in gun range and hasn't started circling around the enemy //or it has started circling around, but the move stopped for some reason (too close to the target, for example) //or if the team has finished a half circle { //may need to tweak mingunrange mingunrangesq = aiuFindMinimumGunRangeSquared(teamShips); victims_center = selCentrePointComputeGeneral((MaxSelection *)victims, &dummy); teams_center = selCentrePointComputeGeneral((MaxSelection *)teamShips, &dummy); destination = aiuGenerateFlankCoordinates(victims_center, teams_center, origin, fsqrt(mingunrangesq)); newMove = aimCreateMoveTeamNoAdd(team, destination, thisMove->formation, FALSE, TRUE); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); thisMove->params.moveatt.destination = destination; return FALSE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessAdvancedAttack Description : Move advanced attacks - sequentially attacks individual targets instead of all targets at once Inputs : team - the team doing the attacking Outputs : Kills lotsa ships Return : Returns TRUE when the team is done attacking ----------------------------------------------------------------------------*/ sdword aimProcessAdvancedAttack(AITeam *team) { AITeamMove *thisMove = team->curMove; SelectCommand *moveTargets = thisMove->params.advatt.targets; SelectCommand *teamShips = team->shipList.selection; SelectCommand *target; if (team->shipList.selection->numShips == 0) { //no ships to do anything with, move done aiplayerLog((aiIndex,"Advanced Attack Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { if ((teamShips->numShips) && (moveTargets) && (moveTargets->numShips)) //^^^^^^^^^^^^^ why do I need this? { //if a non-fighter team is attacking fighters /* if ((aiuShipIsFighter(moveTargets->ShipPtr[0])) && (!aiuShipIsFighter(teamShips->ShipPtr[0]))) { */ thisMove->params.advatt.target_ship = NULL; target = /*(AttackCommand *)*/selectMemDupSelection(moveTargets, "duppaa", 0); /* } else if ((moveTargets->numShips < AIM_SQUADRON_NUM_SHIPS) || (teamShips->numShips < AIM_SQUADRON_NUM_SHIPS)) { thisMove->params.advatt.target_ship = thisMove->params.advatt.targets->ShipPtr[0]; target = (AttackCommand *)memAlloc(sizeofAttackCommand(1), "advatt1", 0); target->numTargets = 1; target->TargetPtr[0] = (TargetPtr)thisMove->params.advatt.target_ship; } else { thisMove->params.advatt.target_ship = thisMove->params.advatt.targets->ShipPtr[0]; target = (AttackCommand *)memAlloc(sizeofAttackCommand(2), "advatt2", 0); target->numTargets = 2; target->TargetPtr[0] = (TargetPtr)thisMove->params.advatt.target_ship; target->TargetPtr[1] = (TargetPtr)thisMove->params.advatt.targets->ShipPtr[1]; } */ thisMove->params.advatt.targets = aiuAttack(team, target); thisMove->processing = TRUE; //postfinal - removed because targets now part of the advatt structure // memFree(target); } else { return TRUE; } } else { if ((!thisMove->params.advatt.targets) || (!thisMove->params.advatt.targets->numShips) || (aiuShipsNoLongerAttacking(teamShips))) { aiumemFree(thisMove->params.advatt.targets); return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessHarassAttack Description : Attacks wimpy ships and generally causes havoc Inputs : team - the team doing the havoc causing Outputs : Return : Returns TRUE when the team is done attacking ----------------------------------------------------------------------------*/ sdword aimProcessHarassAttack(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; real32 target_distance_sq; vector target_standoff_pt, approx_team_pos, target_pos; SelectCommand target, *protection; TypeOfFormation formation; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Harass Attack Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { bitClear(team->teamFlags, TEAM_RETREATING); //find the nearest harass target target.ShipPtr[0] = aiuFindHarassTarget(team->shipList.selection); if (target.ShipPtr[0] != NULL) { //find distance to target approx_team_pos = team->shipList.selection->ShipPtr[0]->posinfo.position; target_pos = target.ShipPtr[0]->posinfo.position; target_distance_sq = aiuFindDistanceSquared(approx_team_pos, target_pos); if (target_distance_sq > AIM_MIN_HARASS_ATTACK_DIST_SQ) { //find a standoff point to target target_standoff_pt = aiuFindRangeStandoffPoint(target_pos, approx_team_pos, AIM_HARASS_STANDOFF_DIST); //insert move move in front of this move and move the move pointer back one move // bonus points if you can tell me how many times I wrote "move" in that comment newMove = aimCreateMoveTeamNoAdd(team, target_standoff_pt, AIM_HARASS_MOVE_FORMATION, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); return FALSE; } else { bitSet(team->teamFlags, TEAM_NEEDS_SUPPORT); protection = aiuFindNearbyDangerousEnemyShips(target.ShipPtr[0], AIM_HARASS_PROTECTION_RADIUS); //if the target is protected, attack the protection first, then the target if (protection->numShips > 0) { if (protection->numShips > 1) { formation = AIM_HARASS_MULTITARGET_FORMATION; } else { formation = AIM_HARASS_SINGLETARGET_FORMATION; } newMove = aimCreateAdvancedAttackNoAdd(team, protection, formation,Aggressive,TRUE, TRUE); newMove->events = thisMove->events; if (aiuAttackFeatureEnabled(AIA_KAMIKAZE)) { aieHandlerSetHealthLow(newMove, AIO_FIGHTER_KAMIKAZE_HEALTH, TRUE, FALSE, aihKamikazeHealthLowHandler); } if (protection->numShips == 1) { aieHandlerSetFiring(newMove, TRUE, aihHarassFiringSingleShipHandler); } aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); // memFree(protection); return FALSE; } memFree(protection); target.numShips = 1; //later change back to normal attack??? newMove = aimCreateAdvancedAttackNoAdd(team, selectMemDupSelection(&target, "duppha", 0), AIM_HARASS_SINGLETARGET_FORMATION,Aggressive, TRUE, TRUE); newMove->events = thisMove->events; if (aiuAttackFeatureEnabled(AIA_KAMIKAZE)) { aieHandlerSetHealthLow(newMove, AIO_FIGHTER_KAMIKAZE_HEALTH, TRUE, FALSE, aihKamikazeHealthLowHandler); } aieHandlerSetFiring(newMove, TRUE, aihHarassFiringSingleShipHandler); thisMove->params.harass.target = target.ShipPtr[0]; thisMove->processing = FALSE; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); aiplayerLog((aiIndex,"Harassing! Boom! Boom! Bang! Bang!")); } } return FALSE; } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessDock Description : Moves the team to dock with the nearest dockable ship Inputs : team - the team doing the docking Outputs : Issues a dock command Return : void ----------------------------------------------------------------------------*/ sdword aimProcessDock(AITeam *team) { AITeamMove *thisMove = team->curMove/*, *newMove*/; sdword i = 0, numShips = team->shipList.selection->numShips; real32 maxHealth = 0, actualHealth = 0; ShipPtr ship; SelectCommand *teamselection; sdword dockMoveFlags = thisMove->params.dock.dockmoveFlags; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Dock Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { Ship *dockAt = NULL; DockType dockType; //determine if the ships' health is low for (i = 0; i < team->shipList.selection->numShips; i++) { maxHealth += team->shipList.selection->ShipPtr[i]->staticinfo->maxhealth; actualHealth += team->shipList.selection->ShipPtr[i]->health; } //if the ships' health is low, dock for refuel and repair if (100 *actualHealth/maxHealth < AIM_DOCK_REPAIRHEALTH_TRIGGER) { dockType = DOCK_FOR_BOTHREFUELANDREPAIR; } else { dockType = DOCK_FOR_REFUEL; } if ((dockMoveFlags & dockmoveFlags_AtShip) && (thisMove->params.dock.dockAt)) { dockType = DOCK_AT_SPECIFIC_SHIP; // override all previous decisions dockAt = thisMove->params.dock.dockAt; } if (dockMoveFlags & dockmoveFlags_Stay) { dockType |= DOCK_STAY_TILL_EXPLICITLAUNCH; } if (dockMoveFlags & dockmoveFlags_Instantaneously) { dockType |= DOCK_INSTANTANEOUSLY; } aiuWrapDock(team->shipList.selection, dockType, dockAt); aiplayerLog((aiIndex,"Docking for dockType %d",dockType)); thisMove->params.dock.shipsDocking = selectMemDupSelection(team->shipList.selection, "dockdup", 0); thisMove->processing = TRUE; bitSet(team->teamFlags, TEAM_DOCKING); return FALSE; } else { teamselection = team->shipList.selection; for (i = 0; i < numShips; i++) { ship = teamselection->ShipPtr[i]; if ( (((ship->dockvars.dockship == NULL) && (!aiuShipIsHidden(ship)))) || ((ship->specialFlags & SPECIAL_STAY_TILL_EXPLICITLAUNCH) && ShipIsWaitingForSoftLaunch(ship)) ) { clRemoveShipFromSelection(thisMove->params.dock.shipsDocking, ship); } #if 0 // OLD LOGIC for checking when ships are done docking. Kept for historical reference. //check to see if all the ships have been refueled. if ((ship->fuel/ship->staticinfo->maxfuel > AIM_DOCK_FINISH_FUEL_THRESHOLD) && (!aiuShipIsHidden(ship))) { clRemoveShipFromSelection(thisMove->params.dock.shipsDocking, ship); } #endif } if (!thisMove->params.dock.shipsDocking->numShips) { bitClear(team->teamFlags, TEAM_DOCKING); return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessDefendMothership Description : The team looks for the nearest ship attacking the mothership and attacks it Inputs : team - the team doing the defending Outputs : Dead enemy ships. Lots of 'em Return : TRUE if the all clear command has been given ----------------------------------------------------------------------------*/ sdword aimProcessDefendMothership(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; SelectCommand *target; //if all the ships in the team are gone, let the defense manager clean it up //(later) I hope! :-) if (team->shipList.selection->numShips == 0) { // aiplayerLog((aiIndex,"Defend Mothership Move, Zero size team")); return FALSE; } target = (SelectCommand *)memAlloc(sizeofSelectCommand(1), "defmoshiptarget", 0); target->ShipPtr[0] = aiuFindNearestMothershipAttacker(team->shipList.selection); if (target->ShipPtr[0] != NULL) { target->numShips = 1; newMove = aimCreateAdvancedAttackNoAdd(team, selectMemDupSelection(target, "duppdm", 0), AIM_DEF_MOTHERSHIP_ATTACK_FORMATION,Aggressive,TRUE, TRUE); aieHandlerSetFuelLow(newMove, AID_DEFEND_MOTHERSHIP_FUEL_LOW, TRUE, TRUE, aihGenericFuelLowHandler); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); memFree(target); return FALSE; } else { memFree(target); return TRUE; } } /*----------------------------------------------------------------------------- Name : aimProcessPatrolMove Description : A series of moves is setup and executed. Inputs : team - the team doing the patrol moving Outputs : Creates a whole bunch of moveteam moves Return : TRUE if the patrol move has completed ----------------------------------------------------------------------------*/ sdword aimProcessPatrolMove(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove, *tempMove; udword i, num_points = thisMove->params.patrolmove.path->numPoints, startIndex = thisMove->params.patrolmove.startIndex; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Patrol Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { if (thisMove->params.patrolmove.path->closed) { //in a closed loop path, create all the moves then point the curMove pointer to //the startindex //create the first move newMove = aimCreateMoveTeamIndexNoAdd(team, thisMove->params.patrolmove.path->point[0],0, thisMove->formation,thisMove->tactics,TRUE, FALSE); thisMove->params.patrolmove.loopMove = newMove; newMove->events = thisMove->events; listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); if (startIndex == 0) { tempMove = newMove; } //create all the rest of the moves for (i = 1; i < num_points; i++) { newMove = aimCreateMoveTeamIndexNoAdd(team, thisMove->params.patrolmove.path->point[i],i, thisMove->formation,thisMove->tactics,TRUE,FALSE); newMove->events = thisMove->events; listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); if (startIndex == i) { tempMove = newMove; } } } else { //in open loop paths, ignore previous moves and just start with the //startindex move for (i = startIndex; i < num_points; i++) { newMove = aimCreateMoveTeamIndexNoAdd(team, thisMove->params.patrolmove.path->point[i],i, thisMove->formation,thisMove->tactics,TRUE,TRUE); newMove->events = thisMove->events; listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); if (startIndex == i) { tempMove = newMove; } } } thisMove->processing = TRUE; team->curMove = tempMove; return FALSE; } else { if (thisMove->params.patrolmove.path->closed) { //go through the moveteam moves and set the processing flag to false tempMove = thisMove->params.patrolmove.loopMove; while (tempMove != thisMove) { tempMove->processing = FALSE; tempMove = (AITeamMove *)listGetStructOfNode(tempMove->listNode.next); } team->curMove = thisMove->params.patrolmove.loopMove; return FALSE; } return TRUE; } } /*----------------------------------------------------------------------------- Name : aimProcessActivePatrol Description : Creates a new patrol path for the team and creates the moves to do them Inputs : team - the team doing the active patrol Outputs : Creates a bunch of moves Return : TRUE if the move is done ----------------------------------------------------------------------------*/ sdword aimProcessActivePatrol(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; Path *patrolpath; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Active Patrol Move, Zero Sized Team")); return TRUE; } patrolpath = aiuGeneratePatrolPath(thisMove->params.activepatrol.patroltype); if (patrolpath->numPoints > 0) { newMove = aimCreatePatrolMoveNoAdd(team, patrolpath, 0, thisMove->formation, Aggressive, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } else { memFree(patrolpath); } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessTempGuard Description : Moves the ships into a defensive position and guards against attacks. This move is meant for attack ships that are sitting around waiting for their attack order Inputs : team - the team doing the temp guard Outputs : Creates a whack of moves Return : TRUE if the move is done ----------------------------------------------------------------------------*/ sdword aimProcessTempGuard(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; MaxSelection invadingShips, distressShips; vector origin = {0,0,0}; real32 distance; if (team->shipList.selection->numShips == 0) { bitClear(team->teamFlags, TEAM_TempGuard); aiplayerLog((aiIndex,"Temp Guard Move, Zero Sized Team")); return TRUE; } if (!bitTest(team->teamFlags, TEAM_TempGuard)) { bitSet(team->teamFlags, TEAM_TempGuard); } // if the attack order has been given if (aivarValueGet(aivarFind(aiCurrentAIPlayer->attackVarLabel)) <= -1) { aiplayerLog((aiIndex,"%x, TempGuard: attackVarLabel set to -1, leaving guard", team)); bitClear(team->teamFlags, TEAM_TempGuard); return TRUE; } if (!thisMove->processing) { if (aiCurrentAIPlayer->player->PlayerMothership) { distance = AIM_TEMP_GUARD_MOVE_LOCATION_MULT*(fsqrt(aiCurrentAIPlayer->sphereofinfluence)); /* guardLocation = aiuFindRangeStandoffPoint(aiCurrentAIPlayer->player->PlayerMothership->posinfo.position, origin, AIM_TEMP_GUARD_MOVE_LOCATION_MULT*(fsqrt(aiCurrentAIPlayer->sphereofinfluence))); newMove = aimCreateMoveTeamNoAdd(team, guardLocation, AIM_TEMP_GUARD_MOVE_FORMATION, FALSE, TRUE); */ // **** origin here... get rid of that...// newMove = aimCreateMoveToNoAdd(team, origin, distance,DISTANCE_LIMITED,AIM_TEMP_GUARD_MOVE_FORMATION, AIM_TEMP_GUARD_MOVE_TACTICS, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } thisMove->processing = TRUE; return FALSE; } //this keeps on repeating! do something about it!!! if (aiCurrentAIPlayer->aidInvadingShips) { selSelectionCopy((MaxAnySelection *)&invadingShips, (MaxAnySelection *)aiCurrentAIPlayer->aidInvadingShips); //later also consider corvette attacks MakeShipsOnlyCapital((SelectCommand *)&invadingShips); if (invadingShips.numShips) { newMove = aimCreateAdvancedAttackNoAdd(team, selectMemDupSelection((SelectCommand *)&invadingShips, "dupptg", 0), AIM_TEMP_GUARD_INVADER_FORMATION,Neutral, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); thisMove->processing = FALSE; return FALSE; } } if (aiCurrentAIPlayer->aidDistressShips) { selSelectionCopy((MaxAnySelection *)&distressShips, (MaxAnySelection *)aiCurrentAIPlayer->aidDistressShips); if (aiuRescueShipType((SelectCommand *)&distressShips, team, AdvanceSupportFrigate)) { return FALSE; } if (aiuRescueShipType((SelectCommand *)&distressShips, team, ResourceController)) { return FALSE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessReinforce Description : Moves the team close to the team it's supposed to reinforce, gives the reinforcing ships the same order as the team, and copies the team into the other Inputs : team - the team doing the move Outputs : Return : TRUE if the move is completed ----------------------------------------------------------------------------*/ sdword aimProcessReinforce(AITeam *team) { AITeam *reinforceTeam = team->curMove->params.reinforce.reinforceteam; AITeamMove *thisMove = team->curMove, *reinforceMove = reinforceTeam->curMove, *newMove; sdword i; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Dock Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { //first move the reinforcing team to the location of the team to be reinforced if ((reinforceTeam->shipList.selection->numShips) && (aiuFindDistanceSquared(team->shipList.selection->ShipPtr[0]->posinfo.position, reinforceTeam->shipList.selection->ShipPtr[0]->posinfo.position) > AIM_INTERCEPT_FINISH_DISTSQ)) { newMove = aimCreateInterceptNoAdd(team, reinforceTeam->shipList.selection->ShipPtr[0], 5.0,DELTA_FORMATION,Evasive, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); return FALSE; } //then copy the reinforcing team ships to the team to be reinforced for (i=team->shipList.selection->numShips-1;i>=0;i--) { aitAddShip(reinforceTeam, team->shipList.selection->ShipPtr[i]); growSelectRemoveShipIndex(&team->shipList, i); } dbgAssert(team->shipList.selection->numShips == 0); if (reinforceMove) { reinforceMove->processing = FALSE; if (reinforceTeam->shipList.selection->numShips > 1) { if ((reinforceMove->formation != NO_FORMATION) && (reinforceMove->formation != SAME_FORMATION)) { aiuWrapFormation(reinforceTeam->shipList.selection, reinforceMove->formation); } else if ((reinforceTeam->kasFormation != NO_FORMATION) && (reinforceTeam->kasFormation != SAME_FORMATION)) { aiuWrapFormation(reinforceTeam->shipList.selection, reinforceTeam->kasFormation); } } aiplayerLog((aiIndex,"Reinforcing move #%i", reinforceMove->type)); } //note: the reinforce move does not deal with special casees yet. //code below is for that purpose /* switch (reinforceMove->type) { case MOVE_DONE: //if the team to reinforce is done, this team is done as well... return TRUE; case MOVE_GUARDSHIPS: //add movetoship move //then guard target case MOVE_DEFMOSHIP: //add movetoship move //then recheck. If close enough, add to team case MOVE_TEMPGUARD: //add movetoship move //then add to team case MOVE_GETSHIPS: //add ships to team (check if adding proper ships to get out of // getships move?) case MOVE_FORMATION: //add moveto ship move //command should be different by the time the ships arrive case MOVE_MOVETEAM: case MOVE_PATROLMOVE: case MOVE_ACTIVEPATROL: case MOVE_COUNTSHIPS: case MOVE_ATTACK: case MOVE_ADVANCEDATTACK: case MOVE_FLANKATTACK: case MOVE_HARASSATTACK: case MOVE_FANCYGETSHIPS: case MOVE_DOCK: case MOVE_REINFORCE: case MOVE_VARSET: case MOVE_VARINC: case MOVE_VARDEC: case MOVE_VARWAIT: case MOVE_VARDESTROY: case MOVE_GUARDCOOPTEAM: default: break; }*/ } return TRUE; } /*----------------------------------------------------------------------------- Name : aimProcessSupport Description : Moves the support ship into the vicinity of the ships it is supporting Inputs : team - the supporting team Outputs : May create some new moves if needed Return : TRUE if the move is completed ----------------------------------------------------------------------------*/ sdword aimProcessSupport(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; SelectCommand *ships = thisMove->params.support.ships; vector support_location; real32 dist; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Support Move, Zero Sized Team")); return TRUE; } if ((!ships) || (!ships->numShips)) { //move back to the mothership dist = aiuFindDistanceSquared(team->shipList.selection->ShipPtr[0]->posinfo.position, aiuPlayerMothershipCoords(aiCurrentAIPlayer->player)); if (dist > 100000000) { newMove = aimCreateMoveToNoAdd(team, aiuPlayerMothershipCoords(aiCurrentAIPlayer->player), 8.0, TIME_LIMITED, SAME_FORMATION, Evasive, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } return FALSE; } support_location = aiuFindSafestStandoffPoint(ships, AIM_SUPPORT_SAFE_DISTANCE); if (!vecIsZero(support_location)) { //support location becomes move location newMove = aimCreateMoveToNoAdd(team, support_location, 8.0, TIME_LIMITED, SAME_FORMATION, Evasive, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } else { aiplayerLog((aiIndex,"AI: Random Support Standoff Point")); //generate a random standoff point and store the angle (?) to keep consistency } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessActiveRecon Description : Moves the team to the next nearest blob, counts ships, repeat Inputs : team - the team doing the recon mission Outputs : Creates a few new moves if needed Return : TRUE if the move is done ----------------------------------------------------------------------------*/ sdword aimProcessActiveRecon(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; vector destination; udword chance_of_change_enemyrecon, num_enemy_blobs, tactics_chance; TacticsType tactic; ShipPtr playerMothership = aiCurrentAIPlayer->player->PlayerMothership; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex,"Active Recon Move, Zero Sized Team")); return FALSE; } if (team->shipList.selection->ShipPtr[0]->shiptype == Probe) { //if a probe is farther than 5km from the mothership, //it is considered launched and can't move again. if (playerMothership && (aiuFindDistanceSquared(team->shipList.selection->ShipPtr[0]->posinfo.position, playerMothership->posinfo.position) > 25000000)) { return TRUE; } } if (!thisMove->processing) { tactics_chance = (udword)randyrandom(RAN_AIPlayer, 100); if (tactics_chance < 2) { tactic = Aggressive; } else if (tactics_chance < 9) { tactic = Neutral; } else { tactic = Evasive; } newMove = aimCreateMoveToNoAdd(team, aiuFindEnemyMothershipCoords(aiCurrentAIPlayer->player), 5.0, TIME_LIMITED, SAME_FORMATION, tactic, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); thisMove->processing = TRUE; return FALSE; } if (playerMothership) { if (thisMove->params.activerecon.outwards) { if (thisMove->params.activerecon.enemyrecon) { destination = aiuFindStandoffOfNextNearestEnemyBlobOut(playerMothership, team->shipList.selection->ShipPtr[0]); } else { destination = aiuFindStandoffOfNextNearestBlobOut(playerMothership, team->shipList.selection->ShipPtr[0]); } if (vecIsZero(destination)) { thisMove->params.activerecon.outwards = FALSE; return FALSE; } newMove = aimCreateMoveTeamNoAdd(team, destination, SAME_FORMATION, /*Evasive,*/ TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } else { if (thisMove->params.activerecon.enemyrecon) { destination = aiuFindStandoffOfNextNearestEnemyBlobIn(playerMothership, team->shipList.selection->ShipPtr[0]); } else { destination = aiuFindStandoffOfNextNearestBlobIn(playerMothership,team->shipList.selection->ShipPtr[0]); } if (vecIsZero(destination)) { thisMove->params.activerecon.outwards = TRUE; return FALSE; } newMove = aimCreateMoveTeamNoAdd(team, destination, SAME_FORMATION, /*Evasive,*/ TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } num_enemy_blobs = aiuGetNumEnemyBlobs(); if (thisMove->params.activerecon.enemyrecon) { chance_of_change_enemyrecon = 100 - 20*num_enemy_blobs; thisMove->params.activerecon.enemyrecon = !(randyrandombetween(RAN_AIPlayer, 0, 100) > chance_of_change_enemyrecon); } else { chance_of_change_enemyrecon = 15*num_enemy_blobs; thisMove->params.activerecon.enemyrecon = randyrandombetween(RAN_AIPlayer, 0, 100) > chance_of_change_enemyrecon; } // newMove = aimCreateCountShipsNoAdd(team, TRUE, TRUE); // newMove->events = thisMove->events; // listAddNodeAfter(&(team->curMove->listNode), &(newMove->listNode), newMove); return FALSE; } return TRUE; } /*----------------------------------------------------------------------------- Name : aimProcessShipRecon Description : Makes the team intercept and peek at a selection of ships Inputs : team - the team doing the peeking Outputs : Creates a few moves - mainly intercept and KILL!!!! Oh... sorry... only intercept... Return : TRUE if the move is done ----------------------------------------------------------------------------*/ sdword aimProcessShipRecon(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; ShipPtr target; SelectCommand *teamships = team->shipList.selection, *moveships = thisMove->params.shiprecon.ships, *nearbyships; udword i; if (!teamships->numShips) { aiplayerLog((aiIndex,"Ship Recon Move, Zero Sized Team")); return TRUE; } //if the ships have died, return TRUE if (!moveships->numShips) { return TRUE; } //first check to see if any of the ships are nearby nearbyships = selectSelectionIntersection(teamships->ShipPtr[0]->collMyBlob->blobShips, moveships); if (nearbyships) { for (i=0;inumShips;i++) { clRemoveShipFromSelection(moveships, nearbyships->ShipPtr[i]); } selectMergeTwoSelections(thisMove->params.shiprecon.foundships, nearbyships, DEALLOC2); thisMove->processing = FALSE; } //if the ships have been found, return TRUE if (!moveships->numShips) { return TRUE; } if (!thisMove->processing) { target = aiuGetClosestShip(moveships, teamships->ShipPtr[0]); newMove = aimCreateInterceptNoAdd(team, target, 5, NO_FORMATION, Evasive, TRUE, TRUE); newMove->events = thisMove->events; listAddNodeAfter(&(team->curMove->listNode), &(newMove->listNode), newMove); thisMove->processing = TRUE; return FALSE; } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessArmada Description : Moves those cool armada ships into the thick of things and kills lots of stuff Inputs : team - the team doing the armada-ing Outputs : Lots of shooting and stuff - creates attack moves and move moves Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessArmada(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; MaxSelection hyperspace; // vector dest_target; // SelectCommand *sel_target; // bool visibility; //choose good target //if unknown, send recon mission to check out // wait for recon to finish //if known, choose attack type (flank, straight, takeout) // attack! //we want to outflank the mothership fleet.... maybe have a fleet analysis or something... hmmm... //maybe add a small fleet analysis in Flank attack? //find weak side... //later - add coordination with recon/support/guard/cooperating team if (!team->shipList.selection->numShips) { //all ships are dead. R.I.P. aiplayerLog((aiIndex,"Armada Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { if (!bitTest(team->teamFlags, TEAM_ARMADA)) { bitSet(team->teamFlags, TEAM_ARMADA); } if (aiCurrentAIPlayer->aiaArmada.targets) { selSelectionCopy((MaxAnySelection *)&hyperspace, (MaxAnySelection *)team->shipList.selection); makeSelectionHyperspaceCapable((SelectCommand *)&hyperspace); // hyperspace if we can if (bitTest(team->teamFlags, TEAM_Hyperspaceable) && (hyperspace.numShips) && (aiCurrentAIPlayer->aifHyperSavings > 0)) { aiplayerLog((aiIndex, "%x, Armada: Creating Hyperspace Flank Attack", team)); newMove = aimCreateFlankAttackNoAdd(team, selectMemDupSelection(aiCurrentAIPlayer->aiaArmada.targets, "duppfah", 0), TRUE, /*SAME_FORMATION, */TRUE, TRUE); } else { aiplayerLog((aiIndex, "%x, Armada: Creating Normal Flank Attack", team)); newMove = aimCreateFlankAttackNoAdd(team, selectMemDupSelection(aiCurrentAIPlayer->aiaArmada.targets, "duppfan", 0), FALSE, /*SAME_FORMATION, */TRUE, TRUE); } newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); thisMove->processing = TRUE; } } else { //later must flesh this one out!!! if (aiCurrentAIPlayer->aiaArmada.targets) { aiplayerLog((aiIndex, "%x, Armada: Still targets %i left, redoing processing", team, aiCurrentAIPlayer->aiaArmada.targets->numShips)); thisMove->processing = FALSE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessControlResources Description : Moves the resource controller (or team... which will most likely only have a resource controller) to optimize resourcer docking Inputs : team - the team that's controlling resourcers Outputs : Creates a few moves Return : TRUE if the move is finished ----------------------------------------------------------------------------*/ sdword aimProcessControlResources(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; vector destination; real32 dist; if (!team->shipList.selection->numShips) { aiplayerLog((aiIndex, "Control Resources Move, Zero ships")); return TRUE; } if (thisMove->params.rescontrol.ships) { // thisMove->params.rescontrol.ships = aiuFindResourceCollectors(); destination = selCentrePointComputeGeneral((MaxSelection *)thisMove->params.rescontrol.ships, &dist); } else { destination = aiuFindResourceControllerDestination(); } dist = aiuFindDistanceSquared(destination, team->shipList.selection->ShipPtr[0]->posinfo.position); if (dist > 100000000) //10 km { newMove = aimCreateMoveTeamNoAdd(team, destination, NO_FORMATION, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessSwarmAttack Description : Controls the attack portion of the P2 swarm attack Inputs : team - the team that's swarming Outputs : Moves ships around Return : TRUE if the move is finished ----------------------------------------------------------------------------*/ sdword aimProcessSwarmAttack(AITeam *team) { AITeamMove *thisMove = team->curMove; SelectCommand *targets = thisMove->params.swarmatt.targets; SelectCommand *teamShips = team->shipList.selection; udword i, fuellow; for (i=0;inumShips;) { ShipPtr ship; if (aitMsgReceived(team, "DockNow")) { if (team->msgSender) if (team->msgSender->shipList.selection->numShips) { aitDeleteAllTeamMoves(team); team->curMove = aimCreateDock(team, dockmoveFlags_Stay|dockmoveFlags_AtShip, team->msgSender->shipList.selection->ShipPtr[0], TRUE, TRUE); return FALSE; } } //if we're already fighting, if (targets) { //lower chance of refuelling fuellow = randyrandombetween(RAN_AIPlayer, 14, 18); } else { //high chance of refuelling fuellow = randyrandombetween(RAN_AIPlayer, 18, 25); } if (!aiuFuelAbove(teamShips->ShipPtr[i], fuellow) || !aiuHealthAbove(teamShips->ShipPtr[i], 50)) { ship = teamShips->ShipPtr[i]; //put ship into defense team aitAddShip(team->cooperatingTeam, teamShips->ShipPtr[i]); //add the ship to the cooperating team's newSwarmers structure growSelectAddShip(&team->cooperatingTeam->curMove->params.swarmdef.newSwarmers, teamShips->ShipPtr[i]); //remove the ship from the current team growSelectRemoveShipIndex(&team->shipList, i); growSelectRemoveShip(&thisMove->params.swarmatt.newSwarmers, ship); //aiplayerLog((1, "Attack %x: Ship moved from offense to defense", team)); // aitCheckShips(team->cooperatingTeam, ship); } else { i++; } } if (!teamShips->numShips) { //we're either waiting for ships, or all ships are dead return FALSE; } if (targets && targets->numShips && aiuShipsCloseToEnemyMothership(aiCurrentAIPlayer->player, targets, 4400)) { aiumemFree(targets); } //if targets are dead, get the next targets if (!targets || !targets->numShips) { targets = aiuFindSwarmerTarget(team); if (targets) { //if there are globally assigned targets if (bitTest(team->teamFlags, TEAM_SwarmTarget)) { //copy them locally, delete them and clear the swarmtargets flag thisMove->params.swarmatt.othertargets = selectMemDupSelection(aiCurrentAIPlayer->Targets, "othertarg", 0); aiumemFree(aiCurrentAIPlayer->Targets); bitClear(team->teamFlags, TEAM_SwarmTarget); } } else if (singlePlayerGameInfo.currentMission == 8) { //uses normal code to find swarm targets in mission 8 targets = aiuFindSwarmTargets(teamShips, randyrandombetween(RAN_AIPlayer, 1, 3), FALSE); } else { //uses harass code to find target in mission 7 targets = aiuFindSwarmTargets(teamShips, 1, TRUE); } if (targets && targets->numShips) { //set the target type // thisMove->params.swarmatt.targettype = targets->ShipPtr[0]->shiptype; //give attack command to all swarmers if ((isShipOfClass(targets->ShipPtr[0], CLASS_Corvette)) || (isShipOfClass(targets->ShipPtr[0], CLASS_Fighter))) { aiuSplitAttack(teamShips, targets); } else { aiuWrapAttack(teamShips, targets); } thisMove->params.swarmatt.targets = targets; } else { //temporary... maybe move the ships back to the guards thisMove->params.swarmatt.targets = NULL; } } else if (thisMove->params.swarmatt.newSwarmers.selection->numShips) { //give attack move to new swarmers //old swarmers continue what they're doing aiuWrapAttack(thisMove->params.swarmatt.newSwarmers.selection, targets); } thisMove->params.swarmatt.newSwarmers.selection->numShips = 0; return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessSwarmDefense Description : Controls the defense portion of the swarm attack Inputs : team - the team that's defense swarming Outputs : Moves ships around Return : TRUE if the move is finished ----------------------------------------------------------------------------*/ sdword aimProcessSwarmDefense(AITeam *team) { AITeamMove *thisMove = team->curMove; SelectCommand *teamShips = team->shipList.selection; MaxSelection dockships, guardships; paramsSwarmDefense *params = &thisMove->params.swarmdef; AITeam *newPodTeam; ShipPtr ship; udword i, fuellow; if (!teamShips->numShips) { //we're either waiting for ships, or all ships are dead return FALSE; } if (aitMsgReceived(team, "DockNow")) { if (team->msgSender) if (team->msgSender->shipList.selection->numShips) { aitDeleteAllTeamMoves(team); team->curMove = aimCreateDock(team, dockmoveFlags_Stay|dockmoveFlags_AtShip, team->msgSender->shipList.selection->ShipPtr[0], TRUE, TRUE); return FALSE; } } if (!params->Pods->numShips) { //pod has been destroyed, find another newPodTeam = aitFindNewPod(team); if (newPodTeam) { selSelectionCopy((MaxAnySelection *)params->Pods, (MaxAnySelection *)newPodTeam->shipList.selection); // aitMoveSwarmersToNewPod(team, newPodTeam); // return TRUE; } else { return FALSE; } } dockships.numShips = 0; guardships.numShips = 0; for (i=0; inumShips;i++) { ship = teamShips->ShipPtr[i]; fuellow = randyrandombetween(RAN_AIPlayer, 45, 65); //if the swarmer isn't already docking and it's fuel is below fuellow // or it's health is below 50 // or the defense swarm is in full refuel mode // and the swarmer's fuel is below 85 if ((!ship->dockvars.dockship) && ((!aiuFuelAbove(ship, fuellow) || !aiuHealthAbove(teamShips->ShipPtr[i], 50) || (params->full_refuel && !aiuFuelAbove(ship, 85))))) { //add the swarmer to a list of to be dockers selSelectionAddSingleShip(&dockships, ship); //if the ship was guarding, remove it from the guarding list if (params->guarding) clRemoveShipFromSelection(params->guarding, ship); } //else if the swarmer isn't already guarding the pod else if ((!ship->dockvars.dockship) && ((!params->guarding) || (!ShipInSelection(params->guarding, ship)))) { selSelectionAddSingleShip(&guardships, ship); } } if (dockships.numShips) { if (dockships.numShips > 7) { tutGameMessage("Swarm_BigDock"); } aiuSwarmDock((SelectCommand *)&dockships, params->Pods); } if (guardships.numShips) { params->guarding = selectMergeTwoSelections(params->guarding, (SelectCommand *)&guardships, DEALLOC1); aiuWrapProtect((SelectCommand *)&guardships, params->Pods); } // if there are guarding ships and //if swarmers are on full attack or new ships have arrived or the attacking team has targets if (params->guarding && ((params->full_attack) || (params->newSwarmers.selection->numShips) || (team->cooperatingTeam->curMove->params.swarmatt.targets) || (team->cooperatingTeam->curMove->params.swarmatt.othertargets))) { //give attackers all the guarding ships for (i=0;/*(inewSwarmers.selection->numShips)&&*/(params->guarding->numShips);i++) { aitMoveSwarmShipDefenseToAttack(team->cooperatingTeam, team, params->guarding->ShipPtr[0]); } params->newSwarmers.selection->numShips = 0; } if (params->guarding && ((params->full_attack)|| ((team->cooperatingTeam->curMove->params.swarmatt.targets)&&(!team->cooperatingTeam->shipList.selection->numShips)))) { //just put the remaining guarding ships into attack team for (i=0;iguarding->numShips;) { aitMoveSwarmShipDefenseToAttack(team->cooperatingTeam, team, params->guarding->ShipPtr[0]); } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessSwarmPod Description : Moves the P2 Pod around and acts as a control center for the other swarmer teams Inputs : team - the pod team Outputs : Moving and silly things like that Return : TRUE if the move is finished ----------------------------------------------------------------------------*/ sdword aimProcessSwarmPod(AITeam *team) { AITeam *attackSwarm = team->cooperatingTeam, *defenseSwarm = team->cooperatingTeam->cooperatingTeam; paramsSwarmDefense *defParams = &defenseSwarm->curMove->params.swarmdef; AITeamMove *thisMove = team->curMove, *newMove; SelectCommand /**enemyShips,*/ *targets; // udword numShips, i; vector current_location, target_location, destination, zerovec = {0,0,0}; real32 avg_size, dist; aiuFindArmadaTarget(&target_location, &targets, team->shipList.selection); current_location = selCentrePointComputeGeneral((MaxSelection *)team->shipList.selection, &avg_size); if (team->shipList.selection->numShips) { if (aitMsgReceived(team, "P2MothershipBlowin")) { MaxSelection filtered; filtered.numShips = 0; aiuFilterDisabledShips(team->shipList.selection, &filtered); RemoveShipsFromDoingStuff(&universe.mainCommandLayer,(SelectCommand *)&filtered); spHyperspaceSelectionOut((SelectCommand *)&filtered); spHyperspaceDelay = 0.0f; return TRUE; } // mothership assault code /* if (singlePlayerGameInfo.currentMission == 8) { if (!thisMove->processing) { //first move - move the ship towards the armada (mothership or powerbase) //find the flanking coordinates destination = aiuGenerateFlankCoordinates(target_location, current_location, zerovec, 10000); //create a move to move to those coordinates (with a wait) newMove = aimCreateMoveTeamNoAdd(team, destination, NO_FORMATION, FALSE, TRUE); aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); thisMove->processing = TRUE; } else if (!vecIsZero(team->shipList.selection->ShipPtr[0]->moveTo)) { //the pod is moving //when near the armada, stop the pod and refuel all the swarmers if (aiuFindDistanceSquared(target_location, current_location) < 225000000) { aiuWrapHalt(team->shipList.selection); defParams->full_refuel = TRUE; thisMove->params.swarmpod.first_attack = TRUE; } } else if (thisMove->params.swarmpod.first_attack) { if (defParams->guarding) { numShips = defParams->guarding->numShips; } else { numShips = 0; } //if all swarmers have fueled up if (numShips == defenseSwarm->shipList.selection->numShips) { defParams->full_refuel = FALSE; //if all other defense swarmers are ready to attack if (aitAllDefenseSwarmersFull()) { thisMove->params.swarmpod.first_attack = FALSE; defParams->full_attack = TRUE; //move the swarmers to the attack team for (i=0; iguarding->ShipPtr[0]); } //move the attack swarmers into the battle area. Boom boom bang bang! if (attackSwarm->shipList.selection->numShips) { newMove = aimCreateMoveTeamNoAdd(attackSwarm, target_location, NO_FORMATION, FALSE, TRUE); aitAddmoveBeforeAndMakeCurrent(attackSwarm, newMove, attackSwarm->curMove); } } } //the enemy is too close for comfort else if (aiuFindDistanceSquared(target_location, current_location) < 80000000) { defParams->full_refuel = FALSE; thisMove->params.swarmpod.first_attack = FALSE; defParams->full_attack = TRUE; aitMoveAllSwarmShipsDefenseToAttack(defenseSwarm, attackSwarm); newMove = aimCreateMoveTeamNoAdd(attackSwarm, target_location, NO_FORMATION, FALSE, TRUE); aitAddmoveBeforeAndMakeCurrent(attackSwarm, newMove, attackSwarm->curMove); } } } else {*/ // we treat the pod as a simple support ship if (!thisMove->processing) { aitMoveAllSwarmShipsDefenseToAttack(defenseSwarm, attackSwarm); thisMove->processing = TRUE; } destination = selCentrePointComputeGeneral((MaxSelection *)attackSwarm->shipList.selection, &avg_size); dist = aiuFindDistanceSquared(destination, team->shipList.selection->ShipPtr[0]->posinfo.position); if (dist > 225000000) { newMove = aimCreateMoveToNoAdd(team, destination, 5000.0, DISTANCE_LIMITED, NO_FORMATION, Evasive, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } // if ((aiCurrentAIPlayer->aiplayerFrameCount & 31) == 0) // { // thisMove->processing = FALSE; // } /* }*/ /* enemyShips = aiuFindNearbyEnemyShips(team->shipList.selection->ShipPtr[0], 8000); if (enemyShips->numShips) { if (!attackSwarm->shipList.selection->numShips && defenseSwarm->shipList.selection->numShips) { sdword numGuardingShips; if (defParams->guarding) { numGuardingShips = defParams->guarding->numShips; } else { numGuardingShips = 0; } //temporary... later do something more secure //obviously numShips will always be equal to numships if ((numGuardingShips > 0) && (numShips <= numGuardingShips)) { for (i=0; iguarding->ShipPtr[0]); } } } } //if no enemies around at all, reset to the beginning else if ((attackSwarm->shipList.selection->numShips) && (attackSwarm->curMove->type == MOVE_SWARMATTACK) && (!attackSwarm->curMove->params.swarmatt.targets)) { ++thisMove->params.swarmpod.attack_delay; if (thisMove->params.swarmpod.attack_delay > 5) { aitMoveAllSwarmShipsAttackToDefense(attackSwarm, defenseSwarm); defParams->full_attack = FALSE; thisMove->params.swarmpod.attack_delay = 0; thisMove->processing = FALSE; } }*/ } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessResourceVolume Description : Moves the resource collectors around to optimize resource collection within a volume Inputs : team - the resource collecting team Outputs : Moves ships around in a most productive way Return : TRUE if the move is complete (the volume is completely resourced) ----------------------------------------------------------------------------*/ sdword aimProcessResourceVolume(AITeam *team) { AITeamMove *thisMove = team->curMove; Resource *resource, *biggestResource; SelectCommand selone; ShipPtr ship; udword i; if (team->shipList.selection->numShips == 0) { return TRUE; } selone.numShips = 1; if ((!thisMove->params.resvolume.volResources) && (!thisMove->params.resvolume.takenResources)) // !thisMove->processing) { thisMove->params.resvolume.volResources = aiuFindResourcesInVolume(thisMove->params.resvolume.volume); thisMove->params.resvolume.takenResources = (ResourceSelection *)memAlloc(sizeofSelectCommand(10), "takeRes", 0); thisMove->params.resvolume.takenResources->numResources = 0; aiplayerLog((aiIndex, "Resetting volResources and takenResources")); // thisMove->processing = TRUE; } if ((thisMove->params.resvolume.volResources) && (thisMove->params.resvolume.volResources->numResources)) { for (i=0; i < team->shipList.selection->numShips;i++) { ship = team->shipList.selection->ShipPtr[i]; if (!aiuShipIsResourcingOrSomething(ship)) { //find the best fit asteroid in the volume resource = aiuFindBestResource(&biggestResource, ship, thisMove->params.resvolume.volResources); if (resource) { //send the resourcer to resource it selone.ShipPtr[0] = ship; aiuWrapCollectResource(&selone, resource); clRemoveTargetFromSelection((SelectAnyCommand *)thisMove->params.resvolume.volResources, (TargetPtr)resource); //maybe this isn't the best way to do it... what if the resource collector gets killed? selSelectionAddSingleShip((MaxSelection *)thisMove->params.resvolume.takenResources, (ShipPtr)resource); bitSet(ship->specialFlags, SPECIAL_Resourcing); // aiplayerLog((aiIndex, "Resourcer %i harvesting best fit", i)); } else { //make tweakable if (100*ship->resources/ship->staticinfo->maxresources > 90) { selone.ShipPtr[0] = ship; aiuWrapDock(&selone, DOCK_TO_DEPOSIT_RESOURCES, NULL); // aiplayerLog((aiIndex, "Resourcer %i docking", i)); } else if (biggestResource) { selone.ShipPtr[0] = ship; aiuWrapCollectResource(&selone, biggestResource); bitSet(ship->specialFlags, SPECIAL_Resourcing); // aiplayerLog((aiIndex, "Resourcer %i harvesting biggest", i)); } } //if no best fit is found and resourcer has > 0 resources, dock! //later, when resource ships have cleaned out the volume, we'll //want to avoid having the ships go dock - so only do that when they're //reasonably full } else if (bitTest(ship->specialFlags, SPECIAL_Finished_Resource)) { if (100*ship->resources/ship->staticinfo->maxresources > 90) { selone.ShipPtr[0] = ship; aiuWrapDock(&selone, DOCK_TO_DEPOSIT_RESOURCES, NULL); // aiplayerLog((aiIndex, "Resourcer %i docking", i)); } bitClear(ship->specialFlags, SPECIAL_Finished_Resource); } } } else { // aiplayerLog((aiIndex, "Finished Resourcing Blob")); return TRUE; } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessActiveResource Description : Activly looks for the best resource pocket and mines the hell out of it Inputs : team - the team doing the resourcing Outputs : Creates some new moves every now and then Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessActiveResource(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; Volume volume; blob *resblob; if (!team->shipList.selection->numShips) { return TRUE; } resblob = aiuFindNearestResourceBlob(team->shipList.selection); if (!resblob) { //***if resources regenerate, return FALSE and just wait... //assume that resources regenerate, just wait. return FALSE; } volume.type = VOLUME_SPHERE; volume.attribs.sphere.center = resblob->centre; volume.attribs.sphere.radius = resblob->radius; newMove = aimCreateResourceVolumeNoAdd(team, volume, FALSE, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessMothershipMove Description : Moves tha mothership around Inputs : team - the mothership team Outputs : Creates a timed move Return : TRUE if the move is finished ----------------------------------------------------------------------------*/ sdword aimProcessMothershipMove(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; vector destination; real32 dist, time; if (!aitNumTeamShips(team)) { aiplayerLog((aiIndex, "Closing Mothership Move")); return TRUE; } if (!aiCurrentAIPlayer->airNumRControllers) { destination = aiuFindResourceControllerDestination(); dist = aiuFindDistanceSquared(destination, aitApproxTeamPos(team)); if ((((aitTeamShipTypeIs(Mothership, team)) && (dist > 200000000)) || //sqrt(20) km ((aitTeamShipTypeIs(Carrier, team)) && (dist > 50000000))) && //sqrt(10) km (aiuDestinationNotNearOtherMothership(destination, 800000000))) { time = frandyrandombetween(RAN_AIPlayer, 20.0, 35.0); newMove = aimCreateMoveToNoAdd(team, destination, time, TIME_LIMITED, NO_FORMATION, Neutral, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } } else if (!thisMove->processing) { destination = aiuFindResourceControllerDestination(); dist = aiuFindDistanceSquared(destination, aitApproxTeamPos(team)); if ((((aitTeamShipTypeIs(Mothership, team)) && (dist > 400000000)) || //20 km ((aitTeamShipTypeIs(Carrier, team)) && (dist > 100000000))) && //10 km (aiuDestinationNotNearOtherMothership(destination, 1600000000))) { newMove = aimCreateMoveToNoAdd(team, destination, 40, TIME_LIMITED, NO_FORMATION, Neutral, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } // thisMove->processing = TRUE; } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessCapture Description : Captures a ship and brings it back to the mothership Inputs : team - the team doing the capturing Outputs : Moves some ships around and stuff... Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessCapture(AITeam *team) { //basically just latch onto the target. //The capture function takes care of the rest. //this move will probably not even be needed.... return TRUE; } /*----------------------------------------------------------------------------- Name : aimProcessActiveCapture Description : Roves the salvage capture corvette around until a nice juicy target is found, then creates a capture move for that target Inputs : team - the team doing the capturing Outputs : Moves some ships around, then creates a new move Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessActiveCapture(AITeam *team) { AITeamMove *thisMove = team->curMove; SelectCommand *target; SelectCommand onesel; if (!team->shipList.selection->numShips) { return TRUE; } if (!thisMove->processing) { //note: later need to add visibility checking for this one... target = aiuFindCaptureTarget(team->shipList.selection); //now check what ships are protecting it onesel.numShips = 1; if (target->ShipPtr[0]) { onesel.ShipPtr[0] = target->ShipPtr[0]; } else if (target->ShipPtr[1]) { onesel.ShipPtr[0] = target->ShipPtr[1]; } else if (target->ShipPtr[2]) { onesel.ShipPtr[0] = target->ShipPtr[2]; } else { //don't bother doing anything return FALSE; } aiuWrapSpecial(team->shipList.selection, &onesel); thisMove->processing = TRUE; //later move towards ships... use support moveto code... //maybe redo aiuFindCaptureTarget //capture best ships... //may also need } else if (!(((udword)universe.totaltimeelapsed) & 15)) { if (((SalCapCorvetteSpec *)(team->shipList.selection->ShipPtr[0]->ShipSpecifics))->salvageState < 3) //dockingstate1 { thisMove->processing = FALSE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessActiveMine Description : Da minin' move - finds a nice juicy area to put a minefield in, then puts it in Inputs : team - the minin' team Outputs : Creates a few new moves Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessActiveMine(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove; // Path *destinations; // vector vec; // SelectCommand *ships; Volume *volume = NULL; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex, "Active Mine Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { //choose type of minelaying - mothership protect, resource patch, enemy path //find the minelaying locations //setup the minevolume thingy //do this a few times, then return TRUE volume = aiuFindBestVolumeToMine(team->shipList.selection); if (!volume) { //if the function couldn't find anything, then mine the center volume = (Volume *)memAlloc(sizeof(Volume), "voltomine", 0); volume->type = VOLUME_SPHERE; vecSet(volume->attribs.sphere.center, 0,0,0); volume->attribs.sphere.radius = 6000; } newMove = aimCreateMineVolumeNoAdd(team, *volume, TRUE, TRUE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); aiumemFree(volume); thisMove->processing = TRUE; return FALSE; } return TRUE; } /*----------------------------------------------------------------------------- Name : aimProcessMineVolume Description : Moves the minelayer corvettes into position to mine a volume and then makes them mine Inputs : team Outputs : Creates a few new moves Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessMineVolume(AITeam *team) { AITeamMove *thisMove = team->curMove, *newMove, *tempMove; Path *minepoints; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex, "Mine Move, Zero Sized Team")); return TRUE; } if (!thisMove->processing) { if (thisMove->params.minevolume.volume.type == VOLUME_SPHERE) { //add two moves - one with the circle slightly wider than the next, so that all the //minelayer corvettes are facing inwards //move to slightly outside the circle minepoints = aiuGenerateCircularPath(team->shipList.selection->numShips, thisMove->params.minevolume.volume.attribs.sphere.center, (thisMove->params.minevolume.volume.attribs.sphere.radius+500), FALSE); newMove = aimCreateMoveTeamSplitNoAdd(team, selectMemDupSelection(team->shipList.selection, "mv1", 0), minepoints, Evasive, TRUE, TRUE); newMove->events = thisMove->events; listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); tempMove = newMove; //move in a little - points the minelayers in the correct direction minepoints = aiuGenerateCircularPath(team->shipList.selection->numShips, thisMove->params.minevolume.volume.attribs.sphere.center, thisMove->params.minevolume.volume.attribs.sphere.radius, FALSE); newMove = aimCreateMoveTeamSplitNoAdd(team, selectMemDupSelection(team->shipList.selection, "mv1", 0), minepoints, Evasive, TRUE, TRUE); newMove->events = thisMove->events; listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); //actual mine move newMove = aimCreateSpecialNoAdd(team, NULL, NO_FORMATION, Evasive, TRUE, TRUE); newMove->events = thisMove->events; listAddNodeBefore(&(thisMove->listNode), &(newMove->listNode), newMove); team->curMove = tempMove; } thisMove->processing = TRUE; } else { // if (!thisMove->params.minevolume.inposition) // { // thisMove->params.minevolume.inposition = TRUE; // aiuWrapSpecial(team->shipList.selection, NULL); // } // else // { // if (aitTeamIsDoingSpecialOp(team) && thisMove->wait) // { // return FALSE; // } // else // { // return TRUE; // } // } return TRUE; } return FALSE; } /*----------------------------------------------------------------------------- Name : aimProcessSpecialDefense Description : Processes teams with special defense ships - cloak generators, gravwell generators Inputs : team - the special team Outputs : May create some new moves Return : TRUE if the move is complete ----------------------------------------------------------------------------*/ sdword aimProcessSpecialDefense(AITeam *team) { AITeam *coopTeam = team->cooperatingTeam; AITeamMove *thisMove = team->curMove, *newMove; if (team->shipList.selection->numShips == 0) { aiplayerLog((aiIndex, "Special Defense Move - Zero sized team")); return TRUE; } // if (!thisMove->processing) // { //find a good team to do special defense with //gravwell - frigate and larger teams with no fighters guarding //cloakgen - frigate or slower teams if (coopTeam == NULL) { team->cooperatingTeam = aitFindGoodCoopTeam(team->shipList.selection->ShipPtr[0]->shiptype); if (team->cooperatingTeam) { team->cooperatingTeamDiedCB = aitSpecialDefenseCoopTeamDiedCB; if (aitTeamShipTypeIs(CloakGenerator, team)) { bitSet(team->cooperatingTeam->teamFlags, TEAM_CloakCoop); // dbgAssert(!team->cooperatingTeam->cooperatingTeam); team->cooperatingTeam->cooperatingTeam = team; team->cooperatingTeam->cooperatingTeamDiedCB = GenericCooperatingTeamDiedCB; } //later - maybe set wait to FALSE, and have this function scan for nearby // cloakables (for the cloak generator) and cloak when appropriate newMove = aimCreateGuardCooperatingTeamNoAdd(team, TRUE, FALSE); newMove->events = thisMove->events; aitAddmoveBeforeAndMakeCurrent(team, newMove, thisMove); } } return FALSE; // } } /*============================================================================= Move Creation Functions: =============================================================================*/ /*----------------------------------------------------------------------------- Name : aimCreateMoveTeam & aimCreateMoveTeamNoAdd Description : Creates a move that moves a team to a location Inputs : team - the team doing the move location - the location to move to wait - whether the move processing waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Calls the command layer move command Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMoveTeamNoAdd(AITeam *team, vector destination, TypeOfFormation formation, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "moveteammove", 0); InitNewMove(newMove,MOVE_MOVETEAM,wait,remove,formation,Neutral,aimProcessMove,NULL,NULL); newMove->params.move.destination = destination; // aiplayerLog((aiIndex,"Created Move Team Move")); return newMove; } AITeamMove *aimCreateMoveTeam(AITeam *team, vector destination, TypeOfFormation formation, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateMoveTeamNoAdd(team, destination, formation, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_MoveTeam(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessMove,NULL,NULL); } /*----------------------------------------------------------------------------- Name : aimCreateMoveTeamIndex Description : Creates an indexed move that moves a team to a location Inputs : team - the team doing the move destination - where to move to index - the move index formation - the formation to use while moving tactics - the type of tactics to use while moving wait - whether or not to wait for the move to complete before moving on remove - whether to remove the move structure after the move has completed Outputs : Creates a new move Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMoveTeamIndexNoAdd(AITeam *team, vector destination, udword index, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "moveteamindex", 0); InitNewMove(newMove,MOVE_MOVETEAMINDEX,wait,remove,formation,tactics,aimProcessMove,NULL,NULL); newMove->params.move.destination = destination; newMove->params.move.index = index; // aiplayerLog((aiIndex,"Created Move Team Index Move")); return newMove; } AITeamMove *aimCreateMoveTeamIndex(AITeam *team, vector destination, udword index, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateMoveTeamIndexNoAdd(team, destination, index, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_MoveTeamIndex(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessMove,NULL,NULL); } /*----------------------------------------------------------------------------- Name : aimCreateMoveTeamSplit Description : Creates a move to split the team's ships Inputs : team - the team doing the split move, ships - the ships to split, destinations - the destinations (corresponding to the ship) Outputs : Creates a new move Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMoveTeamSplitNoAdd(AITeam *team, SelectCommand *ships, Path *destinations, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "moveteamsplit", 0); dbgAssert(destinations->numPoints == ships->numShips); InitNewMove(newMove,MOVE_MOVETEAMSPLIT, wait, remove, NO_FORMATION, tactics, aimProcessMoveSplit, aimMoveSplitShipDied, aimMoveSplitClose); newMove->params.movesplit.destinations = destinations; newMove->params.movesplit.ships = ships; aiplayerLog((aiIndex,"Created Move Split Move")); return newMove; } AITeamMove *aimCreateMoveTeamSplit(AITeam *team, SelectCommand *ships, Path *destinations, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateMoveTeamSplitNoAdd(team, ships, destinations, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } Path *LoadPath(void); // fix later void SavePath(Path *path); void aimFix_MoveTeamSplit(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessMoveSplit, aimMoveSplitShipDied, aimMoveSplitClose); } void aimSave_MoveTeamSplit(AITeamMove *move) { if (move->params.movesplit.ships) SaveSelection((SpaceObjSelection *)move->params.movesplit.ships); if (move->params.movesplit.destinations) SavePath(move->params.movesplit.destinations); } void aimLoad_MoveTeamSplit(AITeamMove *move) { if (move->params.movesplit.ships) move->params.movesplit.ships = (SelectCommand *)LoadSelectionAndFix(); if (move->params.movesplit.destinations) move->params.movesplit.destinations = LoadPath(); } /*----------------------------------------------------------------------------- Name : aimCreateHyperspace & aimCreateHyperspaceNoAdd Description : Creates a move that hyperspaces a team to a location Inputs : team - the team doing the move location - the location to move to wait - whether the move processing waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Calls the command layer move command Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateHyperspaceNoAdd(AITeam *team, vector destination, TypeOfFormation formation, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "movehyperspace", 0); InitNewMove(newMove,MOVE_HYPERSPACE,wait,remove,formation,Neutral,aimProcessHyperspace,NULL,NULL); newMove->params.move.destination = destination; aiplayerLog((aiIndex,"%x Created Hyperspace Move", team)); return newMove; } AITeamMove *aimCreateHyperspace(AITeam *team, vector destination, TypeOfFormation formation, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateHyperspaceNoAdd(team, destination, formation, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_Hyperspace(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessHyperspace,NULL,NULL); } /*----------------------------------------------------------------------------- Name : aimCreateIntercept & aimCreateInterceptNoAdd Description : Creates a move that moves a team to the location of a ship -attempts to intercept the ship by predicting it's location based on previous checks Inputs : team - the team doing the move ship - the ship to intercept interval - how many seconds to wait until checking the move again formation - the formation to do the move in tactics - the tactics to use while doing the move wait - whether the move processing waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Calls the command layer move command Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateInterceptNoAdd(AITeam *team, ShipPtr ship, real32 interval, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "moveintercept", 0); InitNewMove(newMove,MOVE_INTERCEPT,wait,remove,formation,tactics,aimProcessIntercept,aimInterceptShipDied,NULL); newMove->params.intercept.ship = ship; newMove->params.intercept.interval = interval; newMove->params.intercept.next_int = 0.0; // aiplayerLog((aiIndex,"Created Intercept Move")); return newMove; } AITeamMove *aimCreateIntercept(AITeam *team, ShipPtr ship, real32 interval, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateInterceptNoAdd(team, ship, interval, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_Intercept(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessIntercept,aimInterceptShipDied,NULL); move->params.intercept.ship = SpaceObjRegistryGetShip((sdword)move->params.intercept.ship); } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimPreFix_Intercept(AITeamMove *move) { move->params.intercept.ship = SpaceObjRegistryGetID((SpaceObj *)move->params.intercept.ship); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" /*----------------------------------------------------------------------------- Name : aimCreateMoveTo Description : Creates a mve that moves the team toward a location for a certain distance or duration Inputs : team - the team to move, destination - the direction to move the team, Note: destination is always considered to be further than the team would go if the destination is reached before the limiter is reached, the team stops limiter - determines when the move stops, type - what type of move this is, formation - the formation to do the move in tactics - the tactics to use while doing the move wait - whether the move processor waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMoveToNoAdd(AITeam *team, vector destination, real32 limiter, udword type, TypeOfFormation formation, TacticsType tactics, bool wait, bool remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "movemoveto", 0); InitNewMove(newMove, MOVE_MOVETO,wait,remove,formation,tactics,aimProcessMoveTo,NULL,NULL); newMove->params.moveTo.destination = destination; newMove->params.moveTo.limiter = limiter; newMove->params.moveTo.type = type; // aiplayerLog((aiIndex,"Created Moveto Move")); return newMove; } AITeamMove *aimCreateMoveTo(AITeam *team, vector destination, real32 limiter, udword type, TypeOfFormation formation, TacticsType tactics, bool wait, bool remove) { AITeamMove *newMove; newMove = aimCreateMoveToNoAdd(team, destination, limiter, type, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_MoveTo(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessMoveTo,NULL,NULL); } /*----------------------------------------------------------------------------- Name : aimCreateCountShips Description : Creates a move that makes the team count ships within visual range Inputs : team - the team doing the counting wait - whether the move processing waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Creates a new move structure Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateCountShipsNoAdd(AITeam *team, bool8 wait, bool8 remove) { TypeOfFormation formation = SAME_FORMATION; AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "countshipsmove", 0); InitNewMove(newMove,MOVE_COUNTSHIPS,wait,remove,formation,Neutral,aimProcessCountShips,NULL,NULL); // aiplayerLog((aiIndex,"Created Count Ships Move")); return newMove; } AITeamMove *aimCreateCountShips(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateCountShipsNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_CountShips(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessCountShips,NULL,NULL); } /*----------------------------------------------------------------------------- Name : aimCreateFlankAttack Description : Creates a move that makes a team attack from a flanking angle, rather than straight on Inputs : team - the team doing the attacking targets - the selection of attackees hyperspace - if TRUE the flanking is done by hyperspacing wait - whether the move processor waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Creates a new move structure Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateFlankAttackNoAdd(AITeam *team, SelectCommand *targets, bool8 hyperspace, bool8 wait, bool8 remove) { TypeOfFormation formation = SAME_FORMATION; AITeamMove *newMove; if (!aiuTeamFeatureEnabled(team, AIT_FLANK_ATTACK)) { return aimCreateAttackNoAdd(team, targets, formation, wait, remove); } newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "FlankAttackmove", 0); InitNewMove(newMove,MOVE_FLANKATTACK,wait,remove,formation,Neutral,aimProcessFlankAttack,aimFlankAttackShipDied,aimFlankAttackClose); newMove->params.flankatt.targets = targets; newMove->params.flankatt.hyperspace = hyperspace; aiplayerLog((aiIndex,"%x Created Flanking Attack Move", team)); return newMove; } AITeamMove *aimCreateFlankAttack(AITeam *team, SelectCommand *targets, bool8 hyperspace, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateFlankAttackNoAdd(team, targets, hyperspace, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_FlankAttack(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessFlankAttack,aimFlankAttackShipDied,aimFlankAttackClose); } void aimSave_FlankAttack(AITeamMove *move) { if (move->params.flankatt.targets) SaveSelection((SpaceObjSelection *)move->params.flankatt.targets); } void aimLoad_FlankAttack(AITeamMove *move) { if (move->params.flankatt.targets) move->params.flankatt.targets = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateAdvancedAttack Description : Creates a move that makes the team attack an enemy more efficiently Inputs : team - the team doing the attacking targets - the attackees wait - whether the move processor waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Creates a new move structure Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateAdvancedAttackNoAdd(AITeam *team, SelectCommand *targets, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; if (!aiuTeamFeatureEnabled(team, AIT_ADVANCED_ATTACK)) { return aimCreateAttackNoAdd(team, targets, formation, wait, remove); } newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "advancedattackmove", 0); InitNewMove(newMove,MOVE_ADVANCEDATTACK,wait,remove,formation,tactics,aimProcessAdvancedAttack,aimAdvancedAttackShipDied,aimAdvancedAttackClose); newMove->params.advatt.targets = targets; newMove->params.advatt.target_ship = NULL; // aiplayerLog((aiIndex,"Created Advanced Attack Move")); return newMove; } AITeamMove *aimCreateAdvancedAttack(AITeam *team, SelectCommand *target, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateAdvancedAttackNoAdd(team,target,formation,tactics,wait,remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimPreFix_AdvancedAttack(AITeamMove *move) { move->params.advatt.target_ship = SpaceObjRegistryGetID((SpaceObj *)move->params.advatt.target_ship); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" void aimSave_AdvancedAttack(AITeamMove *move) { if (move->params.advatt.targets) SaveSelection((SpaceObjSelection *)move->params.advatt.targets); } void aimLoad_AdvancedAttack(AITeamMove *move) { if (move->params.advatt.targets) move->params.advatt.targets = (SelectCommand *)LoadSelectionAndFix(); } void aimFix_AdvancedAttack(AITeamMove *move) { move->params.advatt.target_ship = SpaceObjRegistryGetShip((sdword)move->params.advatt.target_ship); FixMoveFuncPtrs(move,aimProcessAdvancedAttack,aimAdvancedAttackShipDied,aimAdvancedAttackClose); } /*----------------------------------------------------------------------------- Name : aimCreateMoveAttack Description : Creates a move that attacks a ship, then moves around to flank it. Inputs : team, targets, formation, tactics, wait, remove Advanced boolean variable determines whether the attack is an advanced attack or not. Outputs : Creates a new move Return : The new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMoveAttackNoAdd(AITeam *team, SelectCommand *targets, bool Advanced, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "moveattackmove", 0); InitNewMove(newMove,MOVE_MOVEATTACK,wait,remove,formation,tactics,aimProcessMoveAttack,aimMoveAttackShipDied,aimMoveAttackClose); newMove->params.moveatt.targets = targets; newMove->params.moveatt.target_ship = NULL; vecZeroVector(newMove->params.moveatt.destination); if (Advanced) { bitSet(team->teamFlags, TEAM_AdvancedMoveAttack); } return newMove; } AITeamMove *aimCreateMoveAttack(AITeam *team, SelectCommand *targets, bool Advanced, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateMoveAttackNoAdd(team, targets, Advanced, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimPreFix_MoveAttack(AITeamMove *move) { move->params.moveatt.target_ship = SpaceObjRegistryGetID((SpaceObj *)move->params.moveatt.target_ship); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" void aimFix_MoveAttack(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessMoveAttack,aimMoveAttackShipDied,aimMoveAttackClose); } void aimSave_MoveAttack(AITeamMove *move) { if (move->params.moveatt.targets) SaveSelection((SpaceObjSelection *)move->params.moveatt.targets); } void aimLoad_MoveAttack(AITeamMove *move) { move->params.moveatt.target_ship = SpaceObjRegistryGetShip((sdword)move->params.moveatt.target_ship); if (move->params.moveatt.targets) move->params.moveatt.targets = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateHarassAttack Description : Creates a move that makes the team harass an enemy Inputs : team - the team doing the harassing wait - whether the move processing waits for this move to complete remove - whether the move processor removes this move when it is done Outputs : Creates a new move structure Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateHarassAttack(AITeam *team, bool8 wait, bool8 remove) { TypeOfFormation formation = SAME_FORMATION; AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "harassattackmove", 0); InitNewMove(newMove,MOVE_HARASSATTACK,wait,remove,formation,Neutral,aimProcessHarassAttack,aimHarassAttackShipDied,NULL); newMove->params.harass.target = NULL; // aiplayerLog((aiIndex,"Created Harass Attack Move")); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_HarassAttack(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessHarassAttack,aimHarassAttackShipDied,NULL); move->params.harass.target = SpaceObjRegistryGetShip((sdword)move->params.harass.target); } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimPreFix_HarassAttack(AITeamMove *move) { move->params.harass.target = SpaceObjRegistryGetID((SpaceObj *)move->params.harass.target); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" /*----------------------------------------------------------------------------- Name : aimCreateDock Description : Creates a move that makes the team dock with the nearest dockable ship Inputs : team - the team doing the docking, wait - whether the move processing waits for this move to complete, remove - whether the move processor removes this move when it is done Outputs : Creates a new move structure Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateDockNoAdd(AITeam *team, sdword dockmoveFlags, ShipPtr dockAt, bool8 wait, bool8 remove) { TypeOfFormation formation = AIM_DOCK_DEFAULT_FORMATION; AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "dockmove", 0); InitNewMove(newMove, MOVE_DOCK, wait, remove,formation,Neutral, aimProcessDock, aimDockShipDied, aimDockClose); newMove->params.dock.shipsDocking = NULL; newMove->params.dock.dockmoveFlags = dockmoveFlags; newMove->params.dock.dockAt = dockAt; // aiplayerLog((aiIndex,"Created Dock Move")); return newMove; } AITeamMove *aimCreateDock(AITeam *team, sdword dockmoveFlags, ShipPtr dockAt, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateDockNoAdd(team, dockmoveFlags, dockAt, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimPreFix_Dock(AITeamMove *move) { move->params.dock.dockAt = SpaceObjRegistryGetID((SpaceObj *)move->params.dock.dockAt); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" void aimFix_Dock(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessDock, aimDockShipDied, aimDockClose); move->params.dock.dockAt = SpaceObjRegistryGetShip((sdword)move->params.dock.dockAt); } void aimSave_Dock(AITeamMove *move) { if (move->params.dock.shipsDocking) SaveSelection((SpaceObjSelection *)move->params.dock.shipsDocking); } void aimLoad_Dock(AITeamMove *move) { if (move->params.dock.shipsDocking) move->params.dock.shipsDocking = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateDefendMothership Description : Creates a move that makes a team defend the mothership Inputs : team - the team to do the defending wait - whether the move processing waits for this move to complete remove -whether the move processor removes this move when it is done Outputs : Creates a new move structure Return : The newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateDefendMothershipNoAdd(AITeam *team, bool8 wait, bool8 remove) { TypeOfFormation formation = SAME_FORMATION; AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "defendmoshipmove", 0); InitNewMove(newMove, MOVE_DEFMOSHIP, wait, remove, formation,Neutral,aimProcessDefendMothership, aimDefendMothershipShipDied, aimDefendMothershipClose); newMove->params.defmoship.targets = NULL; // aiplayerLog((aiIndex,"Created Defend Mothership Move")); return newMove; } AITeamMove *aimCreateDefendMothership(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateDefendMothershipNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_DefMoship(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessDefendMothership, aimDefendMothershipShipDied, aimDefendMothershipClose); } void aimSave_DefMoship(AITeamMove *move) { if (move->params.defmoship.targets) SaveSelection((SpaceObjSelection *)move->params.defmoship.targets); } void aimLoad_DefMoship(AITeamMove *move) { if (move->params.defmoship.targets) move->params.defmoship.targets = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreatePatrolMove Description : Creates a move that makes a team patrol a pathway Inputs : team - the team to do the patrolling wait - whether the move processing waits for this move to complete remove - whether the move gets deleted when it is done Outputs : Creates a new move structure Return : The newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreatePatrolMoveNoAdd(AITeam *team, Path *path, udword startIndex, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "patrolmove", 0); InitNewMove(newMove, MOVE_PATROLMOVE, wait, remove,formation,tactics,aimProcessPatrolMove, NULL, aimPatrolMoveClose); newMove->params.patrolmove.path = path; newMove->params.patrolmove.loopMove = NULL; newMove->params.patrolmove.startIndex = startIndex; // aiplayerLog((aiIndex,"Created Patrol Move Move")); return newMove; } AITeamMove *aimCreatePatrolMove(AITeam *team, Path *path, udword startIndex, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreatePatrolMoveNoAdd(team, path, startIndex, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimFix_PatrolMove(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessPatrolMove, NULL, aimPatrolMoveClose); move->params.patrolmove.loopMove = ConvertNumToPointerInList(&savingThisAITeam->moves,(sdword)move->params.patrolmove.loopMove); } void aimPreFix_PatrolMove(AITeamMove *move) { move->params.patrolmove.loopMove = ConvertPointerInListToNum(&savingThisAITeam->moves,move->params.patrolmove.loopMove); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" Path *LoadPath(void); // fix later void SavePath(Path *path); void aimSave_PatrolMove(AITeamMove *move) { if (move->params.patrolmove.path) SavePath(move->params.patrolmove.path); } void aimLoad_PatrolMove(AITeamMove *move) { if (move->params.patrolmove.path) move->params.patrolmove.path = LoadPath(); } /*----------------------------------------------------------------------------- Name : aimCreateActivePatrol Description : Creates a move that sends the team on a patrol that patrols the continuously changing fleet Inputs : team - the team to add the move to, wait - whether to wait for this move to complete, remove - whether to remove the move after it is done Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateActivePatrolNoAdd(AITeam *team, udword patroltype, bool8 wait, bool8 remove) { TypeOfFormation formation = DELTA3D_FORMATION; AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "activepatrol", 0); InitNewMove(newMove, MOVE_ACTIVEPATROL, wait, remove, formation,Neutral,aimProcessActivePatrol, NULL, NULL); newMove->params.activepatrol.patroltype = patroltype; // aiplayerLog((aiIndex,"Created Active Patrol Move")); return newMove; } AITeamMove *aimCreateActivePatrol(AITeam *team, udword patroltype, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateActivePatrolNoAdd(team, patroltype, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ActivePatrol(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessActivePatrol, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateTempGuard Description : Creates the move required for an attack team to become a temporary guard team Inputs : team - the team to do the temp guard, wait - whether to wait for this move to complete, remove - whether to remove the move after it is done Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateTempGuardNoAdd(AITeam *team, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "tempguard", 0); InitNewMove(newMove, MOVE_TEMPGUARD, wait, remove, formation,tactics,aimProcessTempGuard, NULL, NULL); // aiplayerLog((aiIndex,"Created Temp Guard Move")); return newMove; } AITeamMove *aimCreateTempGuard(AITeam *team, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateTempGuardNoAdd(team, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_TempGuard(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessTempGuard, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateReinforce Description : Creates a move to make a team reinforce another team Inputs : team - the team to do the reinforcing, reinforceteam - the team to reinforce wait - whether to wait for this move to complete, remove - whether to remove the move after it is done Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateReinforceNoAdd(AITeam *team, AITeam *reinforceteam, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "reinforce", 0); InitNewMove(newMove, MOVE_REINFORCE, wait, remove, formation,tactics,aimProcessReinforce, NULL, NULL); newMove->params.reinforce.reinforceteam = reinforceteam; // aiplayerLog((aiIndex,"Created Reinforce Move")); return newMove; } AITeamMove *aimCreateReinforce(AITeam *team, AITeam *reinforceteam, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateReinforceNoAdd(team, reinforceteam, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } #pragma warning( 4 : 4047) // turns off "different levels of indirection warning" void aimFix_Reinforce(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessReinforce, NULL, NULL); move->params.reinforce.reinforceteam = AITeamIndexToTeam(savingThisAITeam->aiplayerowner,(sdword)move->params.reinforce.reinforceteam); } void aimPreFix_Reinforce(AITeamMove *move) { move->params.reinforce.reinforceteam = AITeamToTeamIndex(move->params.reinforce.reinforceteam); } #pragma warning( 2 : 4047) // turn back on "different levels of indirection warning" /*----------------------------------------------------------------------------- Name : aimCreateSupport Description : Creates a move to make a team support another team (only for AdvanceSupportFrigates, Repair Corvettes and Resource Controllers) Inputs : team - the team doing the supporting ships - the ships to support formation - the formation to use tactics - the tactics to use wait - whether to wait for this move to complete remove - whether to remove the move after it is done Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateSupportNoAdd(AITeam *team, SelectCommand *ships, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "support", 0); InitNewMove(newMove, MOVE_SUPPORT, wait, remove, formation, tactics, aimProcessSupport, aimSupportShipDied, aimSupportClose); newMove->params.support.ships = ships; // aiplayerLog((aiIndex,"Created Support Move")); return newMove; } AITeamMove *aimCreateSupport(AITeam *team, SelectCommand *ships, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateSupportNoAdd(team, ships, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_Support(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessSupport, aimSupportShipDied, aimSupportClose); } void aimSave_Support(AITeamMove *move) { if (move->params.support.ships) SaveSelection((SpaceObjSelection *)move->params.support.ships); } void aimLoad_Support(AITeamMove *move) { if (move->params.support.ships) move->params.support.ships = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateActiveRecon Description : Creates a move to make a team do active reconaissance Inputs : team - the team doing the reconaissance formation - the formation to use tactics - the tactics to use wait - whether to wait for this move to complete remove - whether to remove the move after it is done Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateActiveReconNoAdd(AITeam *team, bool EnemyRecon, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "actrecon", 0); InitNewMove(newMove, MOVE_ACTIVERECON, wait, remove, formation, tactics, aimProcessActiveRecon, NULL, NULL); newMove->params.activerecon.outwards = TRUE; newMove->params.activerecon.enemyrecon = EnemyRecon; // aiplayerLog((aiIndex,"Created Active Recon Move")); return newMove; } AITeamMove *aimCreateActiveRecon(AITeam *team, bool EnemyRecon, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateActiveReconNoAdd(team, EnemyRecon, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ActiveRecon(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessActiveRecon, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateShipRecon Description : Creates a move to make a team recon a set of ships Inputs : team, ships, formation, tactics, wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateShipReconNoAdd(AITeam *team, SelectCommand *ships, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "shiprecon", 0); InitNewMove(newMove, MOVE_SHIPRECON, wait, remove, formation, tactics, aimProcessShipRecon, aimShipReconShipDied, aimShipReconClose); newMove->params.shiprecon.ships = ships; newMove->params.shiprecon.foundships = NULL; // aiplayerLog((aiIndex, "Created Ship Recon Move")); return newMove; } AITeamMove *aimCreateShipRecon(AITeam *team, SelectCommand *ships, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateShipReconNoAdd(team, ships, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ShipRecon(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessShipRecon, aimShipReconShipDied, aimShipReconClose); } void aimSave_ShipRecon(AITeamMove *move) { if (move->params.shiprecon.ships) SaveSelection((SpaceObjSelection *)move->params.shiprecon.ships); } void aimLoad_ShipRecon(AITeamMove *move) { if (move->params.shiprecon.ships) move->params.shiprecon.ships = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateArmada Description : Creates an active move that takes care of large groups of capital ships Inputs : team - the team doing the armadaing Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateArmadaNoAdd(AITeam *team, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "armada", 0); InitNewMove(newMove, MOVE_ARMADA, wait, remove, formation, tactics, aimProcessArmada, NULL, NULL); aiplayerLog((aiIndex, "%x Created Armada Move", team)); return newMove; } AITeamMove *aimCreateArmada(AITeam *team, TypeOfFormation formation, TacticsType tactics, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateArmadaNoAdd(team, formation, tactics, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_Armada(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessArmada, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateControlResources Description : Creates a move that gets a resource controller to control resources Inputs : team - the Resource Controller team, ships - the ships to control Note: if ships == NULL, the move will control all resourcers wait - whether to wait for the move to finish, remove - whether to delete the move after it's done1 Outputs : Creates a new move Return : The new move that was created as per "Outputs" ----------------------------------------------------------------------------*/ AITeamMove *aimCreateControlResourcesNoAdd(AITeam *team, SelectCommand *ships, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "rescontrol", 0); InitNewMove(newMove, MOVE_CONTROLRESOURCES, wait, remove, NO_FORMATION, Neutral, aimProcessControlResources, aimControlResourcesShipDied, NULL/*aimControlResourcesClose*/); newMove->params.rescontrol.ships = ships; // aiplayerLog((aiIndex, "Created Control Resources Move")); return newMove; } AITeamMove *aimCreateControlResources(AITeam *team, SelectCommand *ships, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateControlResourcesNoAdd(team, ships, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ControlResources(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessControlResources, aimControlResourcesShipDied, NULL/*aimControlResourcesClose*/); } void aimSave_ControlResources(AITeamMove *move) { if (move->params.rescontrol.ships) SaveSelection((SpaceObjSelection *)move->params.rescontrol.ships); } void aimLoad_ControlResources(AITeamMove *move) { if (move->params.rescontrol.ships) move->params.rescontrol.ships = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateSwarmAttack Description : Creates a swarm attack of ships - special code for P2 pirates Inputs : team - the team swarm wait - whether to wait for the move to finish remove - whether the move gets deleted after it's done Outputs : Creates a new move Return : void ----------------------------------------------------------------------------*/ AITeamMove *aimCreateSwarmAttackNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "swarmattack", 0); InitNewMove(newMove, MOVE_SWARMATTACK, wait, remove, NO_FORMATION, Neutral, aimProcessSwarmAttack, aimSwarmAttackShipDied, aimSwarmAttackClose); growSelectInit(&newMove->params.swarmatt.newSwarmers); newMove->params.swarmatt.targets = NULL; newMove->params.swarmatt.othertargets = NULL; // aiplayerLog((aiIndex, "Created Swarm Attack Move")); return newMove; } AITeamMove *aimCreateSwarmAttack(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateSwarmAttackNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_SwarmAttack(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessSwarmAttack, aimSwarmAttackShipDied, aimSwarmAttackClose); } void aimSave_SwarmAttack(AITeamMove *move) { SaveGrowSelection(&move->params.swarmatt.newSwarmers); if (move->params.swarmatt.targets) SaveSelection((SpaceObjSelection *)move->params.swarmatt.targets); if (move->params.swarmatt.othertargets) SaveSelection((SpaceObjSelection *)move->params.swarmatt.othertargets); } void aimLoad_SwarmAttack(AITeamMove *move) { LoadGrowSelectionAndFix(&move->params.swarmatt.newSwarmers); if (move->params.swarmatt.targets) move->params.swarmatt.targets = (SelectCommand *)LoadSelectionAndFix(); if (move->params.swarmatt.othertargets) move->params.swarmatt.othertargets = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateSwarmDefense Description : Creates a swarm defense - special code for P2 pirates to defend fuel pods Inputs : team - the team swarm pod - pointer to the fuel pod wait - whether to wait for the move to finish remove - whether the move gets deleted after it's done Outputs : Creates a new move Return : void ----------------------------------------------------------------------------*/ AITeamMove *aimCreateSwarmDefenseNoAdd(AITeam *team, SelectCommand *pods, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "swarmdefense", 0); InitNewMove(newMove, MOVE_SWARMDEFENSE, wait, remove, NO_FORMATION, Neutral, aimProcessSwarmDefense, aimSwarmDefenseShipDied, aimSwarmDefenseClose); growSelectInit(&newMove->params.swarmdef.newSwarmers); newMove->params.swarmdef.guarding = NULL; newMove->params.swarmdef.Pods = pods; newMove->params.swarmdef.full_refuel = FALSE; newMove->params.swarmdef.full_attack = FALSE; // aiplayerLog((aiIndex, "Created Swarm Defense Move")); return newMove; } AITeamMove *aimCreateSwarmDefense(AITeam *team, SelectCommand *pods, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateSwarmDefenseNoAdd(team, pods, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_SwarmDefense(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessSwarmDefense, aimSwarmDefenseShipDied, aimSwarmDefenseClose); } void aimSave_SwarmDefense(AITeamMove *move) { SaveGrowSelection(&move->params.swarmdef.newSwarmers); if (move->params.swarmdef.guarding) SaveSelection((SpaceObjSelection *)move->params.swarmdef.guarding); if (move->params.swarmdef.Pods) SaveSelection((SpaceObjSelection *)move->params.swarmdef.Pods); } void aimLoad_SwarmDefense(AITeamMove *move) { LoadGrowSelectionAndFix(&move->params.swarmdef.newSwarmers); if (move->params.swarmdef.guarding) move->params.swarmdef.guarding = (SelectCommand *)LoadSelectionAndFix(); if (move->params.swarmdef.Pods) move->params.swarmdef.Pods = (SelectCommand *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateSwarmPod Description : Creates a move to control the swarm pod Inputs : team, wait, remove Outputs : A new move is created Return : The new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateSwarmPodNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "swarmpod", 0); InitNewMove(newMove, MOVE_SWARMPOD, wait, remove, NO_FORMATION, Neutral, aimProcessSwarmPod, NULL, NULL); newMove->params.swarmpod.first_attack = FALSE; newMove->params.swarmpod.attack_delay = 0; // aiplayerLog((aiIndex, "Created Swarm Pod Move")); return newMove; } AITeamMove *aimCreateSwarmPod(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateSwarmPodNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_SwarmPod(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessSwarmPod, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateResourceVolume Description : Creates a move that makes a team collect resources in a spherical volume Inputs : team - the team doing the resourcing, center - the center of the sphere, radius - the radius of the sphere, strictVolume - whether the volume is strictly adhered to, or if the resourcer is allowed to wander a bit wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateResourceVolumeNoAdd(AITeam *team, Volume volume, bool8 strictVolume, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "resvolume", 0); InitNewMove(newMove, MOVE_RESVOLUME, wait, remove, NO_FORMATION, Neutral, aimProcessResourceVolume, aimResourceVolumeShipDied, aimResourceVolumeClose); newMove->moveResourceDiedFunction = aimResourceVolumeResourceDied; newMove->params.resvolume.volume = volume; newMove->params.resvolume.volResources = NULL; newMove->params.resvolume.takenResources = NULL; newMove->params.resvolume.strictVolume = strictVolume; // aiplayerLog((aiIndex, "Created Resource Volume Move")); return newMove; } AITeamMove *aimCreateResourceVolume(AITeam *team, Volume volume, bool8 strictVolume, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateResourceVolumeNoAdd(team, volume, strictVolume, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ResourceVolume(AITeamMove *move) { FixMoveFuncPtrs(move,aimProcessResourceVolume, aimResourceVolumeShipDied, aimResourceVolumeClose); move->moveResourceDiedFunction = aimResourceVolumeResourceDied; } void aimSave_ResourceVolume(AITeamMove *move) { if (move->params.resvolume.volResources) SaveSelection((SpaceObjSelection *)move->params.resvolume.volResources); if (move->params.resvolume.takenResources) SaveSelection((SpaceObjSelection *)move->params.resvolume.takenResources); } void aimLoad_ResourceVolume(AITeamMove *move) { if (move->params.resvolume.volResources) move->params.resvolume.volResources = (ResourceSelection *)LoadSelectionAndFix(); if (move->params.resvolume.takenResources) move->params.resvolume.takenResources = (ResourceSelection *)LoadSelectionAndFix(); } /*----------------------------------------------------------------------------- Name : aimCreateActiveResource Description : Creates a move to continuously look for the best resource pockets and strip them dry Inputs : team, wait, remove Outputs : Creates a new move Return : The new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateActiveResourceNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "activeres", 0); InitNewMove(newMove, MOVE_ACTIVERES, wait, remove, NO_FORMATION, Neutral, aimProcessActiveResource, NULL, NULL); // aiplayerLog((aiIndex, "Created Active Resource Move")); return newMove; } AITeamMove *aimCreateActiveResource(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateActiveResourceNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ActiveResource(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessActiveResource, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateMothershipMove Description : Creates a new move that gets the mothership to move in productive ways Inputs : team, wait, remove Outputs : Creates a new move Return : The new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMothershipMoveNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "mothership", 0); InitNewMove(newMove, MOVE_MOTHERSHIP, wait, remove, NO_FORMATION, Neutral, aimProcessMothershipMove, aimMothershipMoveShipDied, NULL); // aiplayerLog((aiIndex, "Created Mothership Move")); return newMove; } AITeamMove *aimCreateMothershipMove(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateMothershipMoveNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_MothershipMove(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessMothershipMove, aimMothershipMoveShipDied, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateCapture Description : Creates a move to capture an enemy ship Inputs : team - the team to capture the ship, ship - the ship to capture, wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateCaptureNoAdd(AITeam *team, ShipPtr ship, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "capture", 0); InitNewMove(newMove, MOVE_CAPTURE, wait, remove, NO_FORMATION, Neutral, aimProcessCapture, aimCaptureShipDied, NULL); newMove->params.capture.ship = ship; // aiplayerLog((aiIndex, "Created Capture Move")); return newMove; } AITeamMove *aimCreateCapture(AITeam *team, ShipPtr ship, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateCaptureNoAdd(team, ship, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_Capture(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessCapture, aimCaptureShipDied, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateActiveCapture Description : Moves the salvage capture ships around until a nice meaty target is found Inputs : team - the salvage capture team, wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateActiveCaptureNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "activecapture", 0); InitNewMove(newMove, MOVE_ACTIVECAPTURE, wait, remove, NO_FORMATION, Neutral, aimProcessActiveCapture, NULL, NULL); // aiplayerLog((aiIndex, "Created Active Capture")); return newMove; } AITeamMove *aimCreateActiveCapture(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateActiveCaptureNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ActiveCapture(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessActiveCapture, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateActiveMine Description : Moves the minelayer corvettes to a nice place for mining, then covers the area with a bunch of mines Inputs : team, wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateActiveMineNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "activemine", 0); InitNewMove(newMove, MOVE_ACTIVEMINE, wait, remove, NO_FORMATION, Neutral, aimProcessActiveMine, NULL, NULL); // aiplayerLog((aiIndex, "Created Active Mine")); return newMove; } AITeamMove *aimCreateActiveMine(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateActiveMineNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_ActiveMine(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessActiveMine, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateMineVolume Description : Creates a move to make the team mine a volume in space Inputs : team, volume - the volume to mine, wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateMineVolumeNoAdd(AITeam *team, Volume volume, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "minevol", 0); InitNewMove(newMove, MOVE_MINEVOLUME, wait, remove, NO_FORMATION, Neutral, aimProcessMineVolume, NULL, NULL); newMove->params.minevolume.volume = volume; // aiplayerLog((aiIndex, "Created Mine Volume")); return newMove; } AITeamMove *aimCreateMineVolume(AITeam *team, Volume volume, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateMineVolumeNoAdd(team, volume, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_MineVolume(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessMineVolume, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateSpecialDefense Description : Active Move to properly deal with special ships (cloak generators, gravwell generators) Inputs : team, wait, remove Outputs : Creates a new move Return : the new move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateSpecialDefenseNoAdd(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "specdef", 0); InitNewMove(newMove, MOVE_SPECIALDEFENSE, wait, remove, NO_FORMATION, Neutral, aimProcessSpecialDefense, NULL, NULL); // aiplayerLog((aiIndex, "Created Special Defense")); return newMove; } AITeamMove *aimCreateSpecialDefense(AITeam *team, bool8 wait, bool8 remove) { AITeamMove *newMove; newMove = aimCreateSpecialDefenseNoAdd(team, wait, remove); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_SpecialDefense(AITeamMove *move) { FixMoveFuncPtrs(move, aimProcessSpecialDefense, NULL, NULL); } /*----------------------------------------------------------------------------- Name : aimCreateDeleteTeam Description : Creates a move to delete the current team Inputs : team - the team to delete Outputs : Removes the team and it's moves from memory Return : the newly created move ----------------------------------------------------------------------------*/ AITeamMove *aimCreateDeleteTeamNoAdd(AITeam *team) { AITeamMove *newMove = (AITeamMove *)memAlloc(sizeof(AITeamMove), "delete", 0); InitNewMove(newMove, MOVE_DELETETEAM, TRUE, TRUE, SAME_FORMATION, Neutral, NULL, NULL, NULL); // aiplayerLog((aiIndex, "Created Delete Team Move")); return newMove; } AITeamMove *aimCreateDeleteTeam(AITeam *team) { AITeamMove *newMove; newMove = aimCreateDeleteTeamNoAdd(team); listAddNode(&(team->moves), &(newMove->listNode), newMove); return newMove; } void aimFix_DeleteTeam(AITeamMove *move) { FixMoveFuncPtrs(move,NULL, NULL, NULL); }