/*=============================================================================
    Name    : AIUtilities.h
    Purpose : Utility functions, macros and defines for the Homeworld Computer Player

    Created 6/1/1998 by fpoiker
    Copyright Relic Entertainment, Inc.  All rights reserved.
=============================================================================*/
#ifndef ___AIUTILITIES_H
#define ___AIUTILITIES_H

#include "types.h"
#include "spaceobj.h"
#include "blobs.h"
#include "memory.h"
#include "vector.h"
#include "universe.h"
#include "volume.h"

bool ShipAlreadyHyperspaceOut(Ship *ship);      // don't include singleplayer.h, just this

/*=============================================================================
    Macros:
=============================================================================*/
#define aiumemFree(x)                   if ((x) != NULL) {memFree((x));(x) = NULL;}
#define sizeof_blob_array(x)            sizeof(blob_array) + ((x) - 1) * sizeof(blob *)
#define sizeof_aiblob_array(x)          sizeof(aiblob_array) + ((x) - 1) * sizeof(aiblob *)
#define sizeof_Path(x)                  sizeof(Path) + ((x) - 1) * sizeof(vector)
#define aiuShipIsHidden(x)              bitTest((x)->flags, SOF_Hide)
#define aiuShipIsntSelectable(x)        (bitTest((x)->flags, SOF_Hide|SOF_Disabled|SOF_Crazy) || ShipAlreadyHyperspaceOut(x))
#define aiuShipIsntTargetable(x,player) (bitTest((x)->flags, SOF_Hide|SOF_Hyperspace) || \
                                         ((bitTest((x)->flags, SOF_Cloaked) && (!proximityCanPlayerSeeShip((player), (x))))))

#define aiuShipIsWorthCapturing(x)      ((!isShipOfClass(x, CLASS_Fighter)) && (!isShipOfClass(x, CLASS_Corvette)))

#define num_is_odd(x)                   ((x) & 0x1)

#define blob_to_aiblob(blob, aiblob)    (aiblob)->centre    = (blob)->centre; \
                                        (aiblob)->radius    = (blob)->radius; \
                                        (aiblob)->blobShips = (blob)->blobShips;\
                                        (aiblob)->primaryenemystrength = 0; \
                                        (aiblob)->primaryenemyvalue    = 0; \
                                        (aiblob)->otherenemystrength   = 0; \
                                        (aiblob)->otherenemyvalue      = 0; \
                                        (aiblob)->goodGuystrength      = 0; \
                                        (aiblob)->goodGuyvalue         = 0;

#define aiuFuelAbove(ship, level)       ((100.0 * ((ship)->fuel/(ship)->staticinfo->maxfuel)) > (level))
#define aiuHealthAbove(ship, level)     ((100.0 * ((ship)->health*(ship)->staticinfo->oneOverMaxHealth)) > (level))

#define aiuNewSelection(sel, size, string)  \
                                        (sel) = (SelectCommand *)memAlloc(sizeofSelectCommand((size)), (string), 0);\
                                        (sel)->numShips = 0;
#define aiuNewPyroSelection(sel, size, string)  \
                                        (sel) = (SelectCommand *)memAlloc(sizeofSelectCommand((size)), (string), Pyrophoric);\
                                        (sel)->numShips = 0;


#define aiuRandomRange(prob, range)     randyrandombetween(RAN_AIPlayer, ((prob)-(range)), ((prob)+(range)))

#define aiuGameTimePassed(time)         (universe.totaltimeelapsed > (time))

#define aiuEnableResourceFeature(x)     (bitSet(aiplayer->ResourceFeatures, (x)))
#define aiuEnableAttackFeature(x)       (bitSet(aiplayer->AttackFeatures, (x)))
#define aiuEnableDefenseFeature(x)      (bitSet(aiplayer->DefenseFeatures, (x)))
#define aiuEnableTeamFeature(team, x)   (bitSet((team)->TeamFeatures, (x)))
#define aiuDisableResourceFeature(x)     (bitClear(aiplayer->ResourceFeatures, (x)))
#define aiuDisableAttackFeature(x)       (bitClear(aiplayer->AttackFeatures, (x)))
#define aiuDisableDefenseFeature(x)      (bitClear(aiplayer->DefenseFeatures, (x)))
#define aiuDisableTeamFeature(team, x)   (bitSet((team)->TeamFeatures, (x)))
#define aiuResourceFeatureEnabled(x)    (bitTest(aiCurrentAIPlayer->ResourceFeatures, (x)))
#define aiuAttackFeatureEnabled(x)      (bitTest(aiCurrentAIPlayer->AttackFeatures, (x)))
#define aiuDefenseFeatureEnabled(x)     (bitTest(aiCurrentAIPlayer->DefenseFeatures, (x)))
#define aiuTeamFeatureEnabled(team, x)  (bitTest((team)->TeamFeatures, (x)))

/*=============================================================================
    Constant Definitions:
=============================================================================*/
//#define NUM_FAST_PATROL_PATHPOINTS  4
#define FASTPATROL_STANDOFFDIST     2500

//flags for random standoff points
#define RSP_NORMAL      0
#define RSP_NEAR        1
#define RSP_FAR         2

//vulnerable ships flags
#define ALL_VULNERABLE_SHIPS    0
#define LARGE_VULNERABLE_SHIPS  1


#define ORIGIN_VECTOR {0,0,0}

/*=============================================================================
    Structures:
=============================================================================*/
typedef struct Path
{
    udword numPoints;
    bool   closed;
    vector point[1];
} Path;


/*=============================================================================
    Utility Functions:
=============================================================================*/
/*-----------------------------------------------------------------------------
    Coordinate and Vector Utility Functions:
-----------------------------------------------------------------------------*/
//generates a random vector
vector aiuGenerateRandomVector(void);

//generates a random standoff point
vector aiuGenerateRandomStandoffPoint(vector center, real32 radius, vector origin, udword flags);

//generates coordinates for a flank attack
vector aiuGenerateFlankCoordinates(vector center, vector origin, vector referencevec, real32 radius);

//finds the square of the distance between two points
real32 aiuFindDistanceSquared(vector point1, vector point2);

//finds a point that is within a range of a given destination
vector aiuFindRangeStandoffPoint(vector destination, vector location, real32 range);

//creates a path struct with every point at (-REALlyBig, -REALlyBig, -REALlyBig)
Path *aiuCreatePathStruct(udword numPoints, bool closed);

// allocates memory for and returns a new path (a perfect copy of the existing path)
Path *aiuPathDupe(Path *existing);

//adds a point to a path
void aiuAddPointToPath(vector point, udword pointnum, Path *path);

Path *aiuGenerateCircularPath(udword num_points, vector center, real32 radius, bool closed);

/*-----------------------------------------------------------------------------
    General Utility Functions:
-----------------------------------------------------------------------------*/
void aiuMoveShipSelection(MaxSelection *dest, MaxSelection *source, udword num);

/*-----------------------------------------------------------------------------
    Ship Related Utility Functions:
-----------------------------------------------------------------------------*/
//rescues (reinforces) a certain ship
bool aiuRescueShip(ShipPtr ship, struct AITeam *team);

//rescues (reinforces) a certain shiptype within the selection
ShipPtr aiuRescueShipType(SelectCommand *selection, struct AITeam *team, ShipType type);

//takes out a specific ship
bool aiuTakeoutShip(ShipPtr ship, struct AITeam *team);

//takes out a shiptype within a selection
ShipPtr aiuTakeoutShipType(SelectCommand *selection, struct AITeam *team, ShipType type);

//finds out if the ships are no longer attacking
bool aiuShipsNoLongerAttacking(SelectCommand *selection);

//finds out if the ship is an enemy mothership
bool aiuShipIsAnEnemyMothership(Ship *ship);

//finds out if a ship is not an enemy mothership
bool aiuShipIsntAnEnemyMothership(Ship *ship);

//finds out if any of the selection of ships is a capital ship
bool aiuAnyShipsAreCapitalShips(SelectCommand *ships);

//finds out if the ship is a fighter
bool aiuShipIsFighter(Ship *ship);

//finds out if the ship are not good against fighters
bool aiuShipNotGoodAgainstFighters(Ship *ship);

//function name pretty self explanitory
bool aiuSelectionNotGoodAtKillingTheseTargets(SelectCommand *selection, SelectCommand *targets, real32 strengthratio);

//finds out if any of the selection of ships is hidden
bool aiuShipsAreHidden(SelectCommand *selection);

//filters out any ship that is disabled
udword aiuFilterDisabledShips(SelectCommand *selection, MaxSelection *filtered);

//filters out any ship that isn't selectable
udword aiuFilterSelectableShips(SelectCommand *selection, MaxSelection *filtered);

//tells whether any of the selection of ships isn't targetable
bool aiuShipsArentTargetable(SelectCommand *selection);

//returns TRUE if ship is a dangerous ship
bool aiuIsShipDangerous(Ship *ship);

//returns TRUE if the ship is a primary enemy
bool aiuIsShipPrimaryEnemy(Ship *ship);

void aiuRateShip(udword *strength, udword *value, ShipPtr ship);

//Returns the enemy ships found in the mothership blob
SelectCommand *aiuEnemyShipsInMothershipBlob(void);

//finds the nearest enemy ship in the mothership blob
ShipPtr aiuFindNearestMothershipAttacker(SelectCommand *teamShips);

//returns the player's mothership coordinates
vector aiuPlayerMothershipCoords(Player *player);

// Returns the enemy mothership of player
Ship *aiuFindEnemyMothership(Player *player);

// eliminates ships that aren't dangerous to the mothership from the selection
void aiuMakeShipsOnlyDangerousToMothership(SelectCommand *enemyships);

//finds the coordinates of the enemy mothership
vector aiuFindEnemyMothershipCoords(Player *player);

//returns TRUE if ships are less than dist away from the current players' enemy mothership
bool aiuShipsCloseToEnemyMothership(Player *player, SelectCommand *ships, real32 dist);

//finds the safest point a given distance away from the center of the
//selected ships
vector aiuFindSafestStandoffPoint(SelectCommand *ships, real32 distance);

//generates a patrol path for fast ships
Path *aiuGeneratePatrolPath(udword patroltype);

//finds all the unarmed undefended enemy ships
SelectCommand *aiuFindUnarmedUndefendedEnemyShips(void);

//finds all the unarmed enemy ships
SelectCommand *aiuFindUnarmedEnemyShips(void);

//finds the best volume to mine
Volume *aiuFindBestVolumeToMine(SelectCommand *selection);

//finds all of a player's resource collectors
SelectCommand *aiuFindResourceCollectors(void);

//finds an ideal place for the resource controller to go
vector aiuFindResourceControllerDestination(void);

//makes sure no other mothership is moving towards or near this destination
bool aiuDestinationNotNearOtherMothership(vector destination, real32 radiussq);

//finds the slowest ship in the selection
real32 aiuFindSlowestShipMaxSpeed(SelectCommand *ships);

//returns the ship in the selection that is closest to "ship"
ShipPtr aiuGetClosestShip(SelectCommand *selection, ShipPtr ship);

//finds a small selection of unarmed or lightly armed good guy ships
SelectCommand *aiuFindClosestVulnerableGoodGuyShips(ShipPtr ship, udword type);

//weeds out ships that are farther away from a reference point than a specified point
SelectCommand *aiuRejectShipsPastLocation(SelectCommand *selection, vector reference, vector location);

//finds the closest unarmed undefended enemy ship
ShipPtr aiuFindClosestUnarmedUndefendedEnemyShip(ShipPtr ship);

//finds the best unarmed enemy ship
ShipPtr aiuFindBestUnarmedEnemyShip(SelectCommand *teamShips, real32 range);

//finds dangerous enemy ships close to primarytarget
SelectCommand *aiuFindNearbyDangerousEnemyShips(Ship *primarytarget,real32 range);

//makes targets only be primary enemy ships
void aiuMakeShipsOnlyPrimaryEnemyShips(SelectCommand *selection);

//finds the ships attacking "ship"
SelectCommand *aiuFindAttackingShips(ShipPtr ship);

//finds enemy ships close to primarytarget
SelectCommand *aiuFindNearbyEnemyShips(Ship *primarytarget,real32 range);

//finds the most likely enemy target to harass
ShipPtr aiuFindHarassTarget(SelectCommand *teamShips);

//finds the juciest target for capturing
//note: SelectCommand structure not used as normal, see function comments
SelectCommand *aiuFindCaptureTarget(SelectCommand *capturingShips);

//finds the nearest target from the aiCurrentAIPlayer->Targets list
SelectCommand *aiuFindSwarmerTarget(struct AITeam *team);

//finds targets for the P2 swarmers
SelectCommand *aiuFindSwarmTargets(SelectCommand *teamShips, udword numTargets, bool harass);

//finds out if a point is within the sphere of influence
bool aiuPointWithinSphereOfInfluence(vector point);

//finds one ship in a group of ships within the computer player's sphere of influence
SelectCommand *aiuFindLeadShipInSphereOfInfluence(vector centre, real32 radiussq);

//finds standoff points to the next nearest blob (going outwards from or inwards towards the source from the holder)
vector aiuFindStandoffOfNextNearestBlobOut(ShipPtr source, ShipPtr holder);
vector aiuFindStandoffOfNextNearestBlobIn(ShipPtr source, ShipPtr holder);
vector aiuFindStandoffOfNextNearestEnemyBlobOut(ShipPtr source, ShipPtr holder);
vector aiuFindStandoffOfNextNearestEnemyBlobIn(ShipPtr source, ShipPtr holder);

//returns all the resources in a particular volume
ResourceSelection *aiuFindResourcesInVolume(Volume volume);

//returns true if resourcer is busy
bool aiuShipIsResourcingOrSomething(ShipPtr ship);

//returns the best resource for the ship to harvest
Resource *aiuFindBestResource(Resource **biggetsResource, ShipPtr ship, ResourceSelection *resources);

//returns a rating for a blob w.r.t resourcing
real32 aiuRateBlobForResourcing(blob *thisBlob);

//finds the best blob to collect resources
bool aiuFindBestResourceBlob(vector *destination);

//finds the nearest resource blob
blob *aiuFindNearestResourceBlob(SelectCommand *ships);

//find the aiblob the ship is in
//returns NULL if the ships are not in the same blob if retentive == TRUE
struct aiblob *aiuFindShipsAIBlob(SelectCommand *ships, bool retentive);

//same as above, but for one ship (doesn't return NULL)
struct aiblob *aiuFindShipAIBlob(ShipPtr ship);

//returns TRUE if the enemy ship is visible
bool aiuEnemyShipIsVisible(ShipPtr ship);

//returns the smallest gun range distance among the armed ships in "ships"
//    Note: This function scales the minimum gun ranges to work better
//          with the move attack command
real32 aiuFindMinimumGunRangeSquared(SelectCommand *ships);

//returns TRUE if the ships in selection 1 are in gun range of their attack targets
bool aiuShipsInGunRangeOfTargets(SelectCommand *selection1);

//returns the number of ships an aiplayer can build according to unit caps
udword aiuUnitCapCanBuildShip(struct AIPlayer *aiplayer, ShipType shiptype, sdword numShips);

/*-----------------------------------------------------------------------------
    Armada Functions:
-----------------------------------------------------------------------------*/
bool aiuFindArmadaTarget(vector *dest, SelectCommand **sel_target, SelectCommand *team_ships);

/*-----------------------------------------------------------------------------
    Wrap Functions:
-----------------------------------------------------------------------------*/
//computer player wrap of the attack command
SelectCommand *aiuAttack(struct AITeam *team, SelectCommand *targets);

//splits the attackers into smaller groups.  Recommended for strikecraft vs strikecraft battles only
void aiuSplitAttack(SelectCommand *attackers, SelectCommand *targets);

//special swarm dock command
void aiuSwarmDock(SelectCommand *ships, SelectCommand *Pods);

bool aiuWrapAttack(SelectCommand *attackers, SelectCommand *targets);
bool aiuWrapMove(SelectCommand *ships, vector destination);
bool aiuWrapDock(SelectCommand *ships, DockType docktype, ShipPtr dockwith);
bool aiuWrapFormation(SelectCommand *ships, TypeOfFormation formation);
bool aiuWrapProtect(SelectCommand *ships, SelectCommand *shipstoguard);
bool aiuWrapSpecial(SelectCommand *ships, SelectCommand *targets);
bool aiuWrapCollectResource(SelectCommand *ships, ResourcePtr resource);
bool aiuWrapSetTactics(SelectCommand *ships, TacticsType tactics);
bool aiuWrapHalt(SelectCommand *ships);
bool aiuWrapScuttle(SelectCommand *ships);
bool aiuWrapSetKamikaze(SelectCommand *ships);

// like aiuWrapFormation, except doesn't filter out hidden ships
bool aiuKasWrapFormation(SelectCommand *ships, TypeOfFormation formation);

//gets the collision blob of the selection of ships
blob *aiuWrapGetCollBlob(SelectCommand *ships);

/*-----------------------------------------------------------------------------
    Enemy Stats Utility Functions:
-----------------------------------------------------------------------------*/
//makes changes in the aiplayer structure if the primary enemy changes
void aiuChangePrimaryEnemy(struct AIPlayer *aiplayer);

//finds cloak capable ships in the gathered enemy statistics
bool aiuFindCloakersInEnemyShipsIAmAwareOf(bool Red_Alert);


/*-----------------------------------------------------------------------------
    Blob Utility Functions:
-----------------------------------------------------------------------------*/
//returns the number of enemy blobs
udword aiuGetNumEnemyBlobs();

//fills the EnemyShipsIAmAwareOf arrays in the aiplayer struct
void aiuUpdateKnowledgeOfEnemyShips(struct AIPlayer *aiplayer);

//creates two arrays of pointers to the blobs containing enemy ship
//and the good guy ships
void aiuCreateBlobArrays(Player *player);

//deletes the two blob arrays
void aiuDeleteBlobArrays(void);

// Returns TRUE if current AI player can build ships of shiptype
bool aiuCanBuildShipType(ShipType shiptype,bool scriptteam);

// Returns TRUE if current AI player already has num ships of shiptype
bool aiuAlreadyHasShipType(ShipType shiptype, udword num);

#endif
