// // implementations of KAS functions // #include #include #include #include "shipselect.h" #include "AITeam.h" #include "KASFunc.h" #include "AIPlayer.h" #include "AIUtilities.h" #include "vector.h" #include "kas.h" #include "Volume.h" #include "Timer.h" #include "CommandWrap.h" #include "AIVar.h" #include "AIMoves.h" #include "FormationDefs.h" #include "randy.h" #include "SinglePlayer.h" #include "font.h" #include "render.h" #include "prim2d.h" #include "ping.h" #include "Objectives.h" #include "univupdate.h" #include "tutor.h" #include "soundevent.h" #include "soundeventdefs.h" #include "speechevent.h" #include "SalCapCorvette.h" #include "hs.h" #include "SaveGame.h" #include "collision.h" #include "mainrgn.h" #include "nis.h" #include "texreg.h" #include "sensors.h" #include "subtitle.h" #include "btg.h" #include "aitrack.h" #include "utility.h" #include "fastmath.h" #include "animatic.h" #include "TradeMgr.h" #include "StringsOnly.h" #include "taskbar.h" #include "DDDFrigate.h" #include "consmgr.h" #include "universe.h" extern char SinglePlayerSavedGamesPath[]; extern sdword CurrentMissionSkillLevel; //extern char *getWord(char *dest, char *source); // Found in researchgui.c // // these are for the placeholder for a real fleet intelligence message window // extern fonthandle selGroupFont2; #define POPUPTEXT_TITLE_COLOR colRGB(255, 255, 255) #define POPUPTEXT_COLOR colRGB(200, 200, 0) #define POPUPTEXT_BACKGROUND colRGB(0, 0, 0) #define POPUPTEXT_BORDER_COLOR colRGB(100, 100, 100) sdword popupTextNumLines = 0; char popupTextLines[POPUPTEXT_MAX_LINES][POPUPTEXT_MAX_LINE_LENGTH+1]; real32 popupTextEndTime; sdword popupTextWidth; // this can help eliminate the need to pass the current team ptr to some functions extern AITeam *CurrentTeamP; extern AITeam *kasUnpausedTeam; // run-time scoping for variables, timers, etc. extern sdword CurrentMissionScope; // what level we're currently executing at extern char CurrentMissionScopeName[]; extern LabelledVector **LabelledVectors; extern sdword LabelledVectorsUsed; extern bool ccCameraTimeoutOverride; nisstatic stat1 = {0, 50, 25, 5, 3, 240, 173, 0.5f, 0.5f, 0.9f, 0.1f, 0.2f, 0.1f, 0.6f, 0.2f, TRUE, FALSE, 0}; //current sensors manager zoom length extern real32 smInitialDistance; //stores the current sensors manager zoom length sdword kasStoreSMInitialDistance = 0; extern real32 SUBMESSAGE_SAFETY_TIMEOUT; extern real32 subMessageReturnedFalseTime; //for fading to black at the end of the game extern real32 nisBlackFadeDest; extern real32 nisBlackFadeRate; void kasfMissionCompleted(void) { if (tutorial == TUTORIAL_ONLY) { //put the student out of it's misery tutorialdone = TRUE; } else { clCommandMessage("MISSION COMPLETED"); // play the end of Mission animatic // if you want to finish a level without hyperspacing, you put the stuff that happens here speechEventCleanup(); singlePlayerMissionCompleteCB(); animBinkPlay(singlePlayerGameInfo.currentMission, singlePlayerGameInfo.currentMission + 1); } } void kasfMissionFailed(void) { //clCommandMessage("MISSION FAILED"); singlePlayerMissionFailedCB(); } void kasfFadeToWhite(void) { soundEventStopSFX(3.0); nisBlackFadeDest = 1.0f; nisBlackFadeRate = 3.0f; nisTaskResume(); } // // for scoping symbol names // static void kasfScopeName(char *scopedName, char *name) { if (!name || strlen(name) < 2) scopedName[0] = 0; else if (toupper(name[0]) == 'G' && name[1] == '_') // user is requesting global scope explicitly strcpy(scopedName, name+2); else if (CurrentMissionScope != KAS_SCOPE_MISSION) // local scope sprintf(scopedName, "%s.%s", CurrentMissionScopeName, name); else // user is in global scope strcpy(scopedName, name); } void kasfVarCreate(char *name) { char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); aivarCreate(scopedName); } void kasfVarCreateSet(char *name, sdword value) { char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); aivarCreate(scopedName); aivarValueSet(aivarFind(scopedName), value); } void kasfVarValueSet(char *name, sdword value) { char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); aivarValueSet(aivarFind(scopedName), value); } void kasfVarValueInc(char *name) { AIVar *var; char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); var = aivarFind(scopedName); aivarValueSet(var, aivarValueGet(var) + 1); } void kasfVarValueDec(char *name) { AIVar *var; char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); var = aivarFind(scopedName); aivarValueSet(var, aivarValueGet(var) - 1); } sdword kasfVarValueGet(char *name) { char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); return aivarValueGet(aivarFind(scopedName)); } void kasfVarDestroy(char *name) { char scopedName[AIVAR_LABEL_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); aivarDestroy(aivarFind(scopedName)); } void kasfCommandMessage(char *message) { clCommandMessage(message); } void kasfTimerCreate(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); timTimerCreate(scopedName); } void kasfTimerSet(char *name, sdword duration) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); timTimerSet(scopedName, duration); } void kasfTimerStart(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); timTimerStart(scopedName); } void kasfTimerCreateSetStart(char *name, sdword duration) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); timTimerCreateSetStart(scopedName, duration); } void kasfTimerStop(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); timTimerStart(scopedName); } sdword kasfTimerRemaining(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); return timTimerRemaining(scopedName); } sdword kasfTimerExpired(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); return timTimerExpired(scopedName); } sdword kasfTimerExpiredDestroy(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); return timTimerExpiredDestroy(scopedName); } void kasfTimerDestroy(char *name) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; // allow for extra scope name -- this might be truncated kasfScopeName(scopedName, name); timTimerDestroy(scopedName); } sdword kasfMsgReceived(char *msg) { // remove the need to pass a team ptr return aitMsgReceived(CurrentTeamP, msg); } void kasfAttackMothership(void) { SelectCommand *target; target = (SelectCommand *)memAlloc(sizeofSelectCommand(1), "targetmoship", 0); // assumes human is player 0 target->ShipPtr[0] = aiuFindEnemyMothership(&universe.players[1]); if (target->ShipPtr[0] != NULL) { target->numShips = 1; aitDeleteAllTeamMoves(CurrentTeamP); aimCreateAttack(CurrentTeamP, target, SAME_FORMATION, TRUE, TRUE); } } void kasfAttack(GrowSelection *targets) { // alloc memory that the move can later free itself SelectCommand *dupeTargets = selectDupSelection(targets->selection); if (dupeTargets->numShips && dupeTargets->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); //*** Note changed to Advanced attack! aimCreateAdvancedAttack(CurrentTeamP, dupeTargets, SAME_FORMATION, CurrentTeamP->kasTactics, TRUE, TRUE); } } // gives a set of ships the attack command // this allows individual ships from a team to attack a target void kasfShipsAttack(GrowSelection *targets, GrowSelection *attackers) { aiuWrapAttack(attackers->selection, targets->selection); } void kasfAttackSpecial(GrowSelection *targets) { // alloc memory that the move can later free itself SelectCommand *dupeTargets = selectDupSelection(targets->selection); if (dupeTargets->numShips && dupeTargets->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateSpecial(CurrentTeamP, dupeTargets, SAME_FORMATION, CurrentTeamP->kasTactics, FALSE, TRUE); } } void kasfMoveAttack(GrowSelection *targets) { //alloc memory that the move can later free itself SelectCommand *dupeTargets = selectDupSelection(targets->selection); if (dupeTargets->numShips && dupeTargets->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateMoveAttack(CurrentTeamP, dupeTargets, TRUE, SAME_FORMATION, CurrentTeamP->kasTactics, TRUE, TRUE); } } /*----------------------------------------------------------------------------- Name : kasfBulgeAttack Description : Finds ships in the current team that are near the enemy ships, and only uses those to attack the enemy. This function is an optimization for Mission 14 (though it could be used anywhere) Inputs : targets - the ships to attack, bulgetargets - the ships that end up being attacked, attackers - the ships in the team that split off to attack radius - the maximum distance the team members have to be in order to attack Outputs : Various ships in the current team get attack orders Return : the number of ships chosen to take out ----------------------------------------------------------------------------*/ sdword kasfBulgeAttack(GrowSelection *targets, GrowSelection *bulgetargets, GrowSelection *attackers, sdword radius) { ShipPtr teamship; SelectCommand *teamships = CurrentTeamP->shipList.selection, *targetships = targets->selection, onesel; MaxSelection tempsel; udword i, j, num_teamships = teamships->numShips, num_targets = targetships->numShips; real32 radiussq = (real32)radius*(real32)radius, distsq; // initialize variables bulgetargets->selection->numShips = 0; attackers->selection->numShips = 0; tempsel.numShips = 0; onesel.numShips = 1; //go through each individual team ship for (i=0; i < num_teamships;i++) { teamship = teamships->ShipPtr[i]; // only use ships that aren't attacking already if (!teamship->command || (teamship->command->ordertype.order != COMMAND_ATTACK)) { // find target ships within the alloted radius for (j=0;j < num_targets;j++) { distsq = aiuFindDistanceSquared(targets->selection->ShipPtr[j]->posinfo.position, teamship->posinfo.position); if (distsq < radiussq) { selSelectionAddSingleShip(&tempsel, targets->selection->ShipPtr[j]); } } // if any targets close enough were found, attack them with this ship if (tempsel.numShips) { onesel.ShipPtr[0] = teamship; aiuWrapAttack(&onesel, (SelectCommand *)&tempsel); // add the ship to the attackers grow selection growSelectAddShip(attackers, teamship); // add each new target to the bulgetargets grow selection for (j=0;jselection->numShips; } void kasfIntercept(GrowSelection *targets) { //alloc memory that the move can later free itself if (targets->selection->numShips && targets->selection->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateIntercept(CurrentTeamP, targets->selection->ShipPtr[0], 2.0, SAME_FORMATION, CurrentTeamP->kasTactics, TRUE, TRUE); } } // for salvage/capture ships void kasfTargetDrop(void) { SelectCommand *selection = CurrentTeamP->shipList.selection; sdword i; for (i=0; inumShips; i++) SalCapDropTarget(selection->ShipPtr[i]); } void kasfAttackFlank(GrowSelection *targets) { // alloc memory that the move can later free itself SelectCommand *dupeTargets = selectDupSelection(targets->selection); if (dupeTargets->numShips && dupeTargets->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateFlankAttack(CurrentTeamP, dupeTargets, FALSE, FALSE, TRUE); } } void kasfAttackHarass(void) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateHarassAttack(CurrentTeamP, FALSE, TRUE); } //sets the swarmers to target mode and adds ships to the target list void kasfSetSwarmerTargets(GrowSelection *targets) { aiumemFree(aiCurrentAIPlayer->Targets); aiCurrentAIPlayer->Targets = selectDupSelection(targets->selection); bitSet(aiCurrentAIPlayer->AlertStatus, ALERT_SWARMER_TARGETS); } void kasfSwarmMoveTo(GrowSelection *targets) { MaxSelection swarmers, Pod; udword i; real32 temp; vector destination; ShipPtr ship; swarmers.numShips = 0; Pod.numShips = 0; //split the teams into swarmers and pods for (i=0;ishipList.selection->numShips;i++) { ship = CurrentTeamP->shipList.selection->ShipPtr[i]; if ((ship->shiptype == P2Swarmer) || (ship->shiptype == P2AdvanceSwarmer)) { selSelectionAddSingleShip(&swarmers, ship); } else { selSelectionAddSingleShip(&Pod, ship); } } destination = selCentrePointComputeGeneral((MaxSelection *)targets->selection, &temp); if (Pod.numShips && swarmers.numShips) { aiuWrapProtect((SelectCommand *)&swarmers, (SelectCommand *)&Pod); aiuWrapMove((SelectCommand *)&Pod, destination); } else if (Pod.numShips) { aiuWrapMove((SelectCommand *)&Pod, destination); } else if (swarmers.numShips) { aiuWrapMove((SelectCommand *)&swarmers, destination); } } void kasfFormationDelta(void) { aiuKasWrapFormation(CurrentTeamP->shipList.selection, DELTA_FORMATION); CurrentTeamP->kasFormation = DELTA_FORMATION; } void kasfFormationBroad(void) { aiuKasWrapFormation(CurrentTeamP->shipList.selection, BROAD_FORMATION); CurrentTeamP->kasFormation = BROAD_FORMATION; } void kasfFormationDelta3D(void) { aiuKasWrapFormation(CurrentTeamP->shipList.selection, DELTA3D_FORMATION); CurrentTeamP->kasFormation = DELTA3D_FORMATION; } void kasfFormationClaw(void) { aiuKasWrapFormation(CurrentTeamP->shipList.selection, CLAW_FORMATION); CurrentTeamP->kasFormation = CLAW_FORMATION; } void kasfFormationWall(void) { aiuKasWrapFormation(CurrentTeamP->shipList.selection, WALL_FORMATION); CurrentTeamP->kasFormation = WALL_FORMATION; } void kasfFormationSphere(void) { aiuKasWrapFormation(CurrentTeamP->shipList.selection, SPHERE_FORMATION); CurrentTeamP->kasFormation = SPHERE_FORMATION; } void kasfFormationCustom(GrowSelection *ships) { aiuKasWrapFormation(ships->selection, CUSTOM_FORMATION); } sdword kasfRandom(sdword lowestNum, sdword highestNum) { if (lowestNum > highestNum) { sdword temp = lowestNum; lowestNum = highestNum; highestNum = temp; } return lowestNum + (ranRandom(RAN_AIPlayer) % (highestNum - lowestNum + 1)); } void kasfGuardMothership(void) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateDefendMothership(CurrentTeamP, FALSE, TRUE); } void kasfGuardShips(GrowSelection *ships) { // alloc memory that the move can later free itself SelectCommand *dupeShips = selectDupSelection(ships->selection); if (dupeShips->numShips && dupeShips->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateGuardShips(CurrentTeamP, dupeShips, FALSE, TRUE); } } void kasfPatrolPath(Path *path) { Path *dupePath = aiuPathDupe(path); aitDeleteAllTeamMoves(CurrentTeamP); aimCreatePatrolMove(CurrentTeamP, dupePath, 0, SAME_FORMATION, CurrentTeamP->kasTactics, FALSE, TRUE); } void kasfPatrolActive(void) { // an intelligent patrol that chooses its own path aitDeleteAllTeamMoves(CurrentTeamP); aimCreateActivePatrol(CurrentTeamP, AIT_SLOW_PATROL, FALSE, TRUE); } void kasfLog(char *string) { aiplayerLog((0,"KAS: %s", string)); } void kasfLogInteger(char *string, sdword integer) { char tempstr[256]; char tempstr2[256]; // ensure not too long and that there is an integer field if (strlen(string) > 200 || !strstr(string, "%d")) return; sprintf(tempstr, "KAS: %s", string); sprintf(tempstr2, tempstr, integer); aiplayerLog((0, tempstr2)); } #if 0 // this function is obsolete now sdword kasfTeamMemberHandle(sdword Index) { sdword numShips; numShips = CurrentTeamP->shipList.selection->numShips; if(Index >= numShips) return 0; return (sdword)(CurrentTeamP->shipList.selection->ShipPtr[Index]); } #endif sdword kasfShipsOrder(GrowSelection *ships) { Ship *ship; if (ships->selection->numShips > 0) { ship = ships->selection->ShipPtr[0]; if (ship->command) { return ship->command->ordertype.order; } } return 0; } sdword kasfShipsOrderAttributes(GrowSelection *ships) { Ship *ship; if (ships->selection->numShips > 0) { ship = ships->selection->ShipPtr[0]; if (ship->command) { return ship->command->ordertype.attributes; } } return 0; } // returns percentage sdword kasfTeamHealthAverage(void) { sdword i, numShips; real32 maxHealth = 0.0, actualHealth = 0.0; if (!CurrentTeamP) return 0; numShips = CurrentTeamP->shipList.selection->numShips; if (!numShips) return 0; for (i = 0; i < numShips; ++i) { maxHealth += CurrentTeamP->shipList.selection->ShipPtr[i]->staticinfo->maxhealth; actualHealth += CurrentTeamP->shipList.selection->ShipPtr[i]->health; } return (sdword) (100 * actualHealth / maxHealth); } // returns percentage sdword kasfTeamHealthLowest(void) { sdword i, numShips; sdword thisOne = 0, lowestOne = 110; if (!CurrentTeamP) return 0; numShips = CurrentTeamP->shipList.selection->numShips; if (!numShips) return 0; for (i = 0; i < numShips; ++i) { thisOne = (sdword) (100 * CurrentTeamP->shipList.selection->ShipPtr[i]->health / CurrentTeamP->shipList.selection->ShipPtr[i]->staticinfo->maxhealth); if (thisOne < lowestOne) lowestOne = thisOne; } return lowestOne; } // returns percentage sdword kasfTeamFuelAverage(void) { sdword i, numShips; real32 maxFuel = 0.0, actualFuel = 0.0; if (!CurrentTeamP) return 0; numShips = CurrentTeamP->shipList.selection->numShips; if (!numShips) return 0; for (i = 0; i < numShips; ++i) { maxFuel += CurrentTeamP->shipList.selection->ShipPtr[i]->staticinfo->maxfuel; actualFuel += CurrentTeamP->shipList.selection->ShipPtr[i]->fuel; } return (sdword) (100 * actualFuel / maxFuel); } // returns percentage sdword kasfTeamFuelLowest(void) { sdword i, numShips; sdword thisOne = 0, lowestOne = 110; if (!CurrentTeamP) return 0; numShips = CurrentTeamP->shipList.selection->numShips; if (!numShips) return 0; for (i = 0; i < numShips; ++i) { thisOne = (sdword) (100 * CurrentTeamP->shipList.selection->ShipPtr[i]->fuel / CurrentTeamP->shipList.selection->ShipPtr[i]->staticinfo->maxfuel); if (thisOne < lowestOne) lowestOne = thisOne; } return lowestOne; } sdword kasfTeamCount(void) { return CurrentTeamP->shipList.selection->numShips; } sdword kasfNewShipsAdded(void) { sdword return_value = (sdword)CurrentTeamP->newships; CurrentTeamP->newships = 0; return return_value; } void kasfGrowSelectionClear(GrowSelection *ships) { kasGrowSelectionClear(ships); } sdword kasfShipsCount(GrowSelection *ships) { return ships->selection->numShips; } sdword kasfPointInside(Volume *volume, hvector *location) { vector position; vecGrabVecFromHVec(position, *location); return volPointInside(volume, &position); } // // given a volume, find all ships inside it. make this the selection. // return the number of ships in this selection. // sdword kasfFindShipsInside(Volume *volume, GrowSelection *ships) { Ship *ship; Node *node; if (ships == NULL) return 0; // wipe the selection clean ships->selection->numShips = 0; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { if (volPointInside(volume, &(ship->posinfo.position))) // add it growSelectAddShip(ships, ship); } node = node->next; } return ships->selection->numShips; } // // given a volume, find all enemy ships inside it. make this the selection. // return the number of ships in this selection. // sdword kasfFindEnemyShipsInside(Volume *volume, GrowSelection *ships) { Ship *ship; Node *node; if (ships == NULL) return 0; // wipe the selection clean ships->selection->numShips = 0; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { if (!ship->playerowner->playerIndex && (!bitTest(ship->flags,SOF_Crazy|SOF_Hide|SOF_Hyperspace|SOF_Disabled)) && volPointInside(volume, &(ship->posinfo.position))) // add it growSelectAddShip(ships, ship); } node = node->next; } return ships->selection->numShips; } // // given a selection of ships, find all enemies within a radius // of those ships. make this the new selection. return the number // of ships in the new selection. // sdword kasfFindEnemiesNearby(GrowSelection *ships, sdword radius) { Ship *medianShip, *ship; real32 rangeSquared = (real32)radius*(real32)radius; Node *node; sdword i; if (ships == NULL || ships->selection == NULL || !(ships->selection->numShips)) return 0; // we should find the median ship, but since we're dealing with a selection // and we probably don't intend the radius to exclude any existing ships, // we'll assume the radius is large enough to consume the whole group from // any (enemy) ship within the group (and then some, since the radius is supposed // to add to the group if anything). this is heavy-duty cheating, but it // saves mucho CPU time if this routine were to be in many regular watch // sections of script code. i = 0; do { medianShip = ships->selection->ShipPtr[i]; ++i; } while (medianShip->playerowner->playerIndex && i < ships->selection->numShips); // not enemy yet // wipe the selection clean ships->selection->numShips = 0; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { // is it an enemy? (simplifying assumption: "is it the human"?) if ((!ship->playerowner->playerIndex) && (!bitTest(ship->flags,SOF_Crazy|SOF_Hide|SOF_Hyperspace|SOF_Disabled))) { // within the radius? if (medianShip == ship || aiuFindDistanceSquared(medianShip->posinfo.position, ship->posinfo.position) <= rangeSquared) { // add it growSelectAddShip(ships, ship); } } } node = node->next; } return ships->selection->numShips; } // // like FindEnemiesNearby, only check the radius relative to the current team, // ignoring what might be in the initial ships list // sdword kasfFindEnemiesNearTeam(GrowSelection *ships, sdword radius) { Ship *medianShip, *ship; real32 rangeSquared = (real32)radius*(real32)radius; Node *node; if (ships == NULL || ships->selection == NULL) return 0; // wipe the selection clean ships->selection->numShips = 0; if (!CurrentTeamP->shipList.selection->numShips) return 0; // // TBD: could try to select a better median ship among the team // medianShip = CurrentTeamP->shipList.selection->ShipPtr[0]; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { // is it an enemy? (simplifying assumption: "is it the human"?) if (!ship->playerowner->playerIndex && (!bitTest(ship->flags,SOF_Crazy|SOF_Hide|SOF_Hyperspace|SOF_Disabled))) { // within the radius? if (medianShip == ship || aiuFindDistanceSquared(medianShip->posinfo.position, ship->posinfo.position) <= rangeSquared) { // add it growSelectAddShip(ships, ship); } } } node = node->next; } return ships->selection->numShips; } // // Find all the ships near a point // sdword kasfFindShipsNearPoint(GrowSelection *ships, hvector *location, sdword radius) { Ship *ship; real32 rangeSquared = (real32)radius*(real32)radius; vector position; Node *node; if (ships == NULL || ships->selection == NULL || location == NULL) return 0; vecGrabVecFromHVec(position, *location); // wipe the selection clean ships->selection->numShips = 0; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { // is it an ship of some kind? if (!bitTest(ship->flags,SOF_Crazy|SOF_Hide|SOF_Hyperspace|SOF_Disabled)) { // within the radius? if (aiuFindDistanceSquared(position, ship->posinfo.position) <= rangeSquared) { // add it growSelectAddShip(ships, ship); } } } node = node->next; } return ships->selection->numShips; } // // combine FindShipsInside and FindEnemiesNearby because they commonly go together // sdword kasfFindEnemiesInside(Volume *volume, GrowSelection *ships, sdword neighborRadius) { return kasfFindEnemyShipsInside(volume, ships); // return kasfFindEnemiesNearby(ships, neighborRadius); //else // return 0; } void kasfTeamSkillSet(sdword skillLevel) { // Falko, please implement this! // CurrentTeamP->skillLevel = skillLevel; } sdword kasfTeamSkillGet(void) { // Falko, please implement this! // return CurrentTeamP->skillLevel; return 0; } void kasfShipsAttributesBitSet(GrowSelection *ships,sdword attributes) { SelectCommand *selection = ships->selection; sdword numShips = selection->numShips; sdword i; for (i=0;iShipPtr[i]->attributes,attributes); } } void kasfShipsAttributesBitClear(GrowSelection *ships,sdword attributes) { SelectCommand *selection = ships->selection; sdword numShips = selection->numShips; sdword i; for (i=0;iShipPtr[i]->attributes,attributes); } } void kasfShipsAttributesSet(GrowSelection *ships,sdword attributes) { SelectCommand *selection = ships->selection; sdword numShips = selection->numShips; sdword i; for (i=0;iShipPtr[i]->attributes = attributes; } } void kasfTeamAttributesBitSet(sdword attributes) { sdword i, numShips; Ship *shipP; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { shipP = CurrentTeamP->shipList.selection->ShipPtr[i]; bitSet(shipP->attributes,attributes); } } void kasfTeamAttributesBitClear(sdword attributes) { sdword i, numShips; Ship *shipP; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { shipP = CurrentTeamP->shipList.selection->ShipPtr[i]; bitClear(shipP->attributes,attributes); } } void kasfTeamAttributesSet(sdword attributes) { sdword i, numShips; Ship *shipP; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { shipP = CurrentTeamP->shipList.selection->ShipPtr[i]; shipP->attributes = attributes; } } void kasfTeamMakeCrazy(sdword makecrazy) { sdword i, numShips; Ship *shipP; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { shipP = CurrentTeamP->shipList.selection->ShipPtr[i]; if (makecrazy) { ApplyCareenRotationDirectly(shipP); bitSet(shipP->flags,SOF_Crazy); } else { bitClear(shipP->flags,SOF_Crazy); } } } void kasfDisablePlayerHyperspace(void) { singlePlayerGameInfo.hyperspaceFails = TRUE; } void kasfHoldHyperspaceWindow(bool hold) { spHoldHyperspaceWindow = hold; } void kasfTeamHyperspaceIn(hvector *destination) { if (!CurrentTeamP) return; spHyperspaceSelectionIn(CurrentTeamP->shipList.selection,destination); spHyperspaceDelay = 0.0f; } void kasfTeamHyperspaceInNear(hvector *destination, sdword distance) { vector origin = {0.0,0.0,0.0}; vector dest, hypepoint; hvector finalHyperspacePoint; if (!CurrentTeamP) return; vecGrabVecFromHVec(dest, *destination); hypepoint = aiuGenerateRandomStandoffPoint(dest, (real32)distance, origin, RSP_NORMAL); vecMakeHVecFromVec(finalHyperspacePoint, hypepoint); spHyperspaceSelectionIn(CurrentTeamP->shipList.selection, &finalHyperspacePoint); spHyperspaceDelay = 0.0f; } void kasfHyperspaceDelay(sdword milliseconds) { spHyperspaceDelay = ((real32)milliseconds) / 1000.0f; } void kasfTeamHyperspaceOut(void) { MaxSelection filtered; if (!CurrentTeamP) return; filtered.numShips = 0; aiuFilterDisabledShips(CurrentTeamP->shipList.selection, &filtered); RemoveShipsFromDoingStuff(&universe.mainCommandLayer,(SelectCommand *)&filtered); spHyperspaceSelectionOut((SelectCommand *)&filtered); spHyperspaceDelay = 0.0f; } void kasfTeamSetMaxVelocity(sdword maxVelocity) { sdword i, numShips; Ship *shipP; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { shipP = CurrentTeamP->shipList.selection->ShipPtr[i]; shipP->singlePlayerSpeedLimiter = (real32)maxVelocity; bitSet(shipP->specialFlags,SPECIAL_SinglePlayerLimitSpeed); } } void kasfTeamClearMaxVelocity(void) { sdword i, numShips; Ship *shipP; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { shipP = CurrentTeamP->shipList.selection->ShipPtr[i]; bitClear(shipP->specialFlags,SPECIAL_SinglePlayerLimitSpeed); } } /*----------------------------------------------------------------------------- Name : kasfShipsSetMaxVelocity Description : Same as TeamSetMaxVelocity, except that it works on arbitrary ship selections. Inputs : ships - ships to cap velocity of, be they friendly or enemy. maxVelocity - velocity to cap them at. Outputs : Return : void ----------------------------------------------------------------------------*/ void kasfShipsSetMaxVelocity(GrowSelection *ships, sdword maxVelocity) { sdword i, numShips; Ship *shipP; if (!ships) return; numShips = ships->selection->numShips; for (i = 0; i < numShips; ++i) { shipP = ships->selection->ShipPtr[i]; shipP->singlePlayerSpeedLimiter = (real32)maxVelocity; bitSet(shipP->specialFlags,SPECIAL_SinglePlayerLimitSpeed); } } /*----------------------------------------------------------------------------- Name : kasfShipsClearMaxVelocity Description : Similar to TeamClearMaxVelocity, except that it works on an arbitrary selection of ships. Inputs : ships - ships to cap velocity of, be they friendly or enemy. maxVelocity - velocity to cap them at. Outputs : Return : void ----------------------------------------------------------------------------*/ void kasfShipsClearMaxVelocity(GrowSelection *ships, sdword maxVelocity) { sdword i, numShips; Ship *shipP; if (!ships) return; numShips = ships->selection->numShips; for (i = 0; i < numShips; ++i) { shipP = ships->selection->ShipPtr[i]; bitClear(shipP->specialFlags,SPECIAL_SinglePlayerLimitSpeed); } } /*----------------------------------------------------------------------------- Name : kasfShipsSetDamageFactor Description : Sets a modifier in the ship structure to modify the ammount of damage a ship does. Inputs : ships - ships to modify damage of. damagePercent (0 to 100) - divided by 100 then multiplied by ships damage Outputs : Return : void ----------------------------------------------------------------------------*/ void kasfShipsSetDamageFactor(GrowSelection *ships, sdword damagePercent) { sdword i, numShips; Ship *shipP; if (!ships) return; numShips = ships->selection->numShips; for (i = 0; i < numShips; ++i) { shipP = ships->selection->ShipPtr[i]; shipP->damageModifier = ((real32)damagePercent)/100.0f; bitSet(shipP->specialFlags,SPECIAL_KasSpecialDamageModifier); } } /*----------------------------------------------------------------------------- Name : kasfShipsClearDamageFactor Description : Sets a modifier in the ship structure to modify the ammount of damage a ship does. Inputs : ships - ships to modify damage of. damagePercent (0 to 100) - divided by 100 then multiplied by ships damage Outputs : Return : void ----------------------------------------------------------------------------*/ void kasfShipsClearDamageFactor(GrowSelection *ships) { sdword i, numShips; Ship *shipP; if (!ships) return; numShips = ships->selection->numShips; for (i = 0; i < numShips; ++i) { shipP = ships->selection->ShipPtr[i]; bitClear(shipP->specialFlags,SPECIAL_KasSpecialDamageModifier); } } // this function is a bit of a misnomer: it actually sets the percentage of health // therefore 0 "percentDamaged", actually means the health is at 0 and the ship is dead void kasfTeamSetPercentDamaged(sdword percentDamaged) { sdword i, numShips; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) CurrentTeamP->shipList.selection->ShipPtr[i]->health = CurrentTeamP->shipList.selection->ShipPtr[i]->staticinfo->maxhealth * percentDamaged / 100; } void kasfTeamSetPercentFueled(sdword percentFueled) { sdword i, numShips; if (!CurrentTeamP) return; numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) CurrentTeamP->shipList.selection->ShipPtr[i]->fuel = CurrentTeamP->shipList.selection->ShipPtr[i]->staticinfo->maxfuel * percentFueled / 100; } void kasfMissionSkillSet(sdword skillLevel) { CurrentMissionSkillLevel = skillLevel; } sdword kasfMissionSkillGet(void) { return CurrentMissionSkillLevel; } void kasfRequestShips(char *shipType, sdword numShips) { AITeam *teamp; ShipType st = StrToShipType(shipType); // if (st < 0) // st = LightInterceptor; // make a temp team and get them to reinforce the first team teamp = aitCreate(ScriptTeam); strcpy(teamp->kasLabel, "R"); strncat(teamp->kasLabel, CurrentTeamP->kasLabel, KAS_TEAM_NAME_MAX_LENGTH-1); teamp->kasOrigShipsCount = 0; aimCreateGetShips(teamp, st, (sbyte)numShips, (sdword)REQUESTSHIPS_HIPRI, TRUE, TRUE); aimCreateReinforce(teamp, CurrentTeamP, SAME_FORMATION, CurrentTeamP->kasTactics, TRUE, TRUE); aimCreateDeleteTeam(teamp); } void kasfRequestShipsOriginal(sdword percentOriginal) { AITeam *teamp; sbyte numShips = (sbyte)((CurrentTeamP->kasOrigShipsCount * (real32)percentOriginal * 0.01f) + 0.5f); if (numShips <= 0) { numShips = 1; } // make a temp team and get them to reinforce the first team teamp = aitCreate(ScriptTeam); strcpy(teamp->kasLabel, "R"); strncat(teamp->kasLabel, CurrentTeamP->kasLabel, KAS_TEAM_NAME_MAX_LENGTH); teamp->kasOrigShipsCount = 0; aimCreateGetShips(teamp, CurrentTeamP->kasOrigShipsType, numShips, (sdword)REQUESTSHIPS_HIPRI, TRUE, TRUE); aimCreateReinforce(teamp, CurrentTeamP, SAME_FORMATION, CurrentTeamP->kasTactics, TRUE, TRUE); aimCreateDeleteTeam(teamp); } void kasfReinforceTeamWithShips(struct AITeam *teamtoreinforce,GrowSelection *shipstoadd) { sdword i; sdword numShips = shipstoadd->selection->numShips; AITeamMove *reinforceMove = teamtoreinforce->curMove; for (i=0;ishipList, shipstoadd->selection->ShipPtr[i]); } if (reinforceMove) { reinforceMove->processing = FALSE; } } void kasfReinforce(AITeam *team) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateReinforce(CurrentTeamP, team, SAME_FORMATION, CurrentTeamP->kasTactics, TRUE, TRUE); } void kasfForceCombatStatus(GrowSelection *ships, sdword on) { udword i; if (on) { for (i=0;iselection->numShips;i++) { bitSet(ships->selection->ShipPtr[i]->specialFlags, SPECIAL_ForcedAttackStatus); } } else { for (i=0;iselection->numShips;i++) { bitClear(ships->selection->ShipPtr[i]->specialFlags, SPECIAL_ForcedAttackStatus); } } } sdword kasfThisTeamIs(AITeam *team) { return (team == CurrentTeamP); } sdword kasfTeamCountOriginal(void) { return CurrentTeamP->kasOrigShipsCount; } void kasfTeamGiveToAI(void) { Ship *ship; udword i; if (!CurrentTeamP) return; for (i=0;ishipList.selection->numShips;) { ship = CurrentTeamP->shipList.selection->ShipPtr[i]; aitRemoveShip(CurrentTeamP, ship); growSelectAddShip(&aiCurrentAIPlayer->newships, ship); if (ship->shiptype == Carrier || ship->shiptype == Mothership) { aiCurrentAIPlayer->AICreator = ship; } } } void kasfDisableAIFeature(sdword feature, sdword type) { AIPlayer *aiplayer = aiCurrentAIPlayer; switch (type) { case ResourceFeature: aiuDisableResourceFeature(feature); break; case DefenseFeature: aiuDisableDefenseFeature(feature); break; case AttackFeature: aiuDisableAttackFeature(feature); break; case TeamFeature: aiuDisableTeamFeature(CurrentTeamP,feature); break; default: aiplayerLog((0, "Unknown Feature type being enabled %i, %i", feature, type)); break; } } void kasfEnableAIFeature(sdword feature, sdword type) { AIPlayer *aiplayer = aiCurrentAIPlayer; switch (type) { case ResourceFeature: aiuEnableResourceFeature(feature); break; case DefenseFeature: aiuEnableDefenseFeature(feature); break; case AttackFeature: aiuEnableAttackFeature(feature); break; case TeamFeature: aiuEnableTeamFeature(CurrentTeamP,feature); break; default: aiplayerLog((0, "Unknown Feature type being enabled %i, %i", feature, type)); break; } } void kasfDisableAllAIFeatures(void) { aiCurrentAIPlayer->ResourceFeatures = 0; aiCurrentAIPlayer->DefenseFeatures = 0; aiCurrentAIPlayer->AttackFeatures = 0; // aiCurrentAIPlayer->TeamFeatures = 0; } void kasfEnableAllAIFeatures(void) { aiCurrentAIPlayer->ResourceFeatures = 0xFFFFFFFF; aiCurrentAIPlayer->DefenseFeatures = 0xFFFFFFFF; aiCurrentAIPlayer->AttackFeatures = 0xFFFFFFFF; // aiCurrentAIPlayer->TeamFeatures = 0xFFFFFFFF; } #if 0 void kasfTeamGiveToPlayer(void) { Ship *ship; if (!CurrentTeamP) return; while (CurrentTeamP->shipList.selection->numShips) { ship = CurrentTeamP->shipList.selection->ShipPtr[0]; aitRemoveShip(CurrentTeamP, ship); // remove ship from team - and give to no one so it is free bitSet(ship->flags,SOF_Selectable); // make sure player can select it } } #endif void SelectionSwitchPlayerOwner(SelectCommand *selection) { sdword i; sdword numShips = selection->numShips; Ship *ship; RemoveShipsFromDoingStuff(&universe.mainCommandLayer,selection); for (i=0;iShipPtr[i]; RemoveShipFromBeingTargeted(&universe.mainCommandLayer,ship,REMOVE_PROTECT); // remove ships from being targeted when switching sides if (ship->playerowner == &universe.players[0]) { // going from human's ships to kas ships // Remove ships that are destroyed from any current selection clRemoveShipFromSelection((SelectCommand *)&selSelected,ship); // Remove ships that are destroyed from any hot key groups univRemoveShipFromHotkeyGroup(ship,FALSE); ship->playerowner = &universe.players[1]; ship->attributes |= ATTRIBUTES_Defector; bitClear(ship->flags,SOF_Selectable); if (ship->shiptype == DDDFrigate) { DDDFrigateSwitchSides(ship,1); } } else { // going from kas ships to human ships aiplayerShipDied(ship); ship->playerowner = &universe.players[0]; bitClear(ship->attributes,ATTRIBUTES_Defector); bitClear(ship->flags,SOF_Disabled); bitSet(ship->flags,SOF_Selectable); if (ship->shiptype == DDDFrigate) { DDDFrigateSwitchSides(ship,0); } } } } void kasfTeamSwitchPlayerOwner(void) { if (!CurrentTeamP) return; SelectionSwitchPlayerOwner(CurrentTeamP->shipList.selection); } void kasfShipsSwitchPlayerOwner(GrowSelection *ships) { SelectionSwitchPlayerOwner(ships->selection); } void kasfMoveTo(hvector *destination) { vector dest; vecGrabVecFromHVec(dest,*destination); aitDeleteAllTeamMoves(CurrentTeamP); aimCreateMoveTeam(CurrentTeamP, dest, SAME_FORMATION, FALSE, TRUE); } void kasfShipsMoveTo(GrowSelection *ships, hvector *destination) { vector dest; vecGrabVecFromHVec(dest,*destination); aiuWrapMove(ships->selection, dest); } void kasfTacticsAggressive(void) { CurrentTeamP->kasTactics = Aggressive; aiuWrapSetTactics(CurrentTeamP->shipList.selection, Aggressive); } void kasfTacticsNeutral(void) { CurrentTeamP->kasTactics = Neutral; aiuWrapSetTactics(CurrentTeamP->shipList.selection, Neutral); } void kasfTacticsEvasive(void) { CurrentTeamP->kasTactics = Evasive; aiuWrapSetTactics(CurrentTeamP->shipList.selection, Evasive); } // // returns True if any ship in the team is a given distance from the given location // sdword kasfNearby(hvector *location, sdword distance) { real32 rangeSquared = (real32)distance*(real32)distance; sdword i, numShips; vector loc; vecGrabVecFromHVec(loc,*location); numShips = CurrentTeamP->shipList.selection->numShips; for (i = 0; i < numShips; ++i) { if (aiuFindDistanceSquared(CurrentTeamP->shipList.selection->ShipPtr[i]->posinfo.position, loc) <= rangeSquared) return TRUE; } return FALSE; } // // returns the distance between two points // sdword kasfFindDistance(hvector *location1, hvector *location2) { vector loc1, loc2; real32 distsq; vecGrabVecFromHVec(loc1, *location1); vecGrabVecFromHVec(loc2, *location2); distsq = aiuFindDistanceSquared(loc1, loc2); return (sdword)fsqrt(distsq); } sdword kasfUnderAttackElsewhere(struct AITeam *otherTeam, GrowSelection *attackers) { sdword i; SelectCommand *teamSelection = otherTeam->shipList.selection; Node *curnode = universe.mainCommandLayer.todolist.head; CommandToDo *command; Ship *ship; vector leaderpos; if (attackers == NULL) return 0; // wipe the selection clean attackers->selection->numShips = 0; if (teamSelection->numShips == 0) return 0; // if some of the team is hidden, try other members of the team for (i=0; i < teamSelection->numShips; i++) { if (!bitTest(teamSelection->ShipPtr[i]->flags, SOF_Hide)) { leaderpos = teamSelection->ShipPtr[i]->posinfo.position; break; } } if (i== teamSelection->numShips) { // all the team members are hidden... no attacking happening here. return 0; } // lets walk the command layer and see who's attacking us: while (curnode != NULL) { command = (CommandToDo *)listGetStructOfNode(curnode); if ((command->ordertype.order == COMMAND_ATTACK) || (command->ordertype.attributes & (COMMAND_IS_PASSIVEATTACKING|COMMAND_IS_ATTACKINGANDMOVING))) { if (command->attack) { if (AnyOfTheseShipsAreInSelection(teamSelection,(SelectCommand *)command->attack)) { SelectCommand *attackedby = command->selection; for (i = 0;i < attackedby->numShips; i++) { ship = attackedby->ShipPtr[i]; if (MoveReachedDestinationVariable(ship,&leaderpos,10000.0f)) growSelectAddShipNoDuplication(attackers,ship); } } } } curnode = curnode->next; } return attackers->selection->numShips; } sdword kasfUnderAttack(GrowSelection *attackers) { return kasfUnderAttackElsewhere(CurrentTeamP, attackers); } sdword kasfShipsCountType(GrowSelection *ships, char *shipType) { sdword i, count = 0, numShips = ships->selection->numShips; ShipType st = StrToShipType(shipType); // if (st < 0) // return 0; for (i = 0; i < numShips; ++i) if (ships->selection->ShipPtr[i]->shiptype == st) ++count; return count; } void kasfDock(struct AITeam *withTeam) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateDock(CurrentTeamP, dockmoveFlags_Normal, NULL, FALSE, TRUE); } void kasfDockSupport() { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateDock(CurrentTeamP, dockmoveFlags_Normal, NULL, FALSE, TRUE); } void DockSupportWith(struct AITeam * withTeam,sdword flags) { Ship *dockwith = NULL; if (withTeam->shipList.selection->numShips >= 1) { dockwith = withTeam->shipList.selection->ShipPtr[0]; dbgAssert(dockwith); if (aiuShipIsntSelectable(dockwith)) { dockwith = NULL; } else { flags |= dockmoveFlags_AtShip; } } aitDeleteAllTeamMoves(CurrentTeamP); aimCreateDock(CurrentTeamP, flags, dockwith, FALSE, TRUE); } void kasfDockSupportWith(struct AITeam * withTeam) { DockSupportWith(withTeam,0); } void kasfShipsDockSupportWith(GrowSelection *ships, GrowSelection *withShips) { aiuWrapDock(ships->selection, DOCK_AT_SPECIFIC_SHIP, withShips->selection->ShipPtr[0]); } void kasfDockStay(struct AITeam * withTeam) { DockSupportWith(withTeam,dockmoveFlags_Stay); } void kasfShipsDockStay(GrowSelection *ships, GrowSelection *withShips) { aiuWrapDock(ships->selection, DOCK_AT_SPECIFIC_SHIP|DOCK_STAY_TILL_EXPLICITLAUNCH, withShips->selection->ShipPtr[0]); } void kasfDockStayMothership(void) { Ship *dockwith; if (CurrentTeamP->shipList.selection->numShips >= 1) { dockwith = CurrentTeamP->shipList.selection->ShipPtr[0]->playerowner->PlayerMothership; if ((dockwith) && (!aiuShipIsntSelectable(dockwith))) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateDock(CurrentTeamP, dockmoveFlags_AtShip|dockmoveFlags_Stay, dockwith, FALSE, TRUE); } } } void kasfDockInstant(struct AITeam * withTeam) { //put in print command udword i; for (i=0;ishipList.selection->numShips;i++) { aiplayerLog((0, "Docking Instant Ship Type %i", CurrentTeamP->shipList.selection->ShipPtr[i]->shiptype)); } DockSupportWith(withTeam,dockmoveFlags_Stay|dockmoveFlags_Instantaneously); } void kasfLaunch() { udword i; for (i=0;ishipList.selection->numShips;i++) { bitSet(CurrentTeamP->shipList.selection->ShipPtr[i]->specialFlags, SPECIAL_LaunchedFromKas|SPECIAL_KasCheckDoneLaunching); } aitDeleteAllTeamMoves(CurrentTeamP); aimCreateLaunch(CurrentTeamP, FALSE, TRUE); } sdword kasfTeamDocking(void) { //return bitTest(CurrentTeamP->teamFlags, TEAM_DOCKING); return ((CurrentTeamP->teamFlags & TEAM_DOCKING) != 0); // ensure 0/1 return value } bool ShipReadyForLaunch(Ship *ship) { if ((ship->flags & (SOF_Hide | SOF_Hyperspace)) == SOF_Hide) { if (ShipIsRefuelingAtCarrierMother(ship)) return FALSE; // wait, refueling, we're not done yet! else return TRUE; // ship definitely ready for launch, it is inside another ship } else if ((ship->specialFlags & SPECIAL_STAY_TILL_EXPLICITLAUNCH) && (ShipIsWaitingForSoftLaunch(ship))) { return TRUE; } return FALSE; } bool ShipFinishedLaunching(Ship *ship) { if (ship->specialFlags & SPECIAL_KasCheckDoneLaunching) { return FALSE; } return TRUE; } sdword kasfTeamFinishedLaunching(void) { SelectCommand *selection = CurrentTeamP->shipList.selection; sdword i; if (selection->numShips == 0) { return FALSE; } for (i=0;inumShips;i++) { if (!ShipFinishedLaunching(selection->ShipPtr[i])) { return FALSE; } } return TRUE; } sdword kasfTeamDockedReadyForLaunch(void) { SelectCommand *selection = CurrentTeamP->shipList.selection; sdword i; if (selection->numShips == 0) { return FALSE; } for (i=0;inumShips;i++) { if (!ShipReadyForLaunch(selection->ShipPtr[i])) { return FALSE; } } return TRUE; } // // send to all script teams // void kasfMsgSendAll(char *msg) { AITeam *teamp; sdword i; for (i = 0; i < aiCurrentAIPlayer->teamsUsed; i++) { teamp = aiCurrentAIPlayer->teams[i]; //not really sure we need this... CPUTeams deserve to get messages too. // if ((teamp->teamType == ScriptTeam) || (teamp->teamType == AnyTeam)) aitMsgSend(CurrentTeamP, teamp, msg); } } void kasfMsgSend(struct AITeam *team, char *msg) { aitMsgSend(CurrentTeamP, team, msg); } sdword kasfRUsEnemyCollected(void) { return singlePlayerGameInfo.resourceUnitsCollected; } // serves the "friendly" and "enemy" functions below static sdword kasfFindPlayersShipsOfType(GrowSelection *ships, char *shipType, sdword playerIndex) { Node *node; ShipType st = StrToShipType(shipType); Ship *ship; // if (st < 0) // return 0; if (ships == NULL || ships->selection == NULL) return 0; // wipe the selection clean ships->selection->numShips = 0; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { // 1. is it an enemy? (simplifying assumption: "is it the human"?) // 2. is the right type? if (ship->playerowner->playerIndex == playerIndex && ship->shiptype == st) // add it growSelectAddShip(ships, ship); } node = node->next; } return ships->selection->numShips; } // (enemy == human) sdword kasfFindEnemyShipsOfType(GrowSelection *ships, char *shipType) { return kasfFindPlayersShipsOfType(ships, shipType, 0); } // (friendly == not human) sdword kasfFindFriendlyShipsOfType(GrowSelection *ships, char *shipType) { return kasfFindPlayersShipsOfType(ships, shipType, 1); } // serves the "friendly" and "enemy" functions below static sdword kasfFindPlayersShipsOfClass(GrowSelection *ships, char *shipClass, sdword playerIndex) { Node *node; ShipClass sc = StrToShipClass(shipClass); Ship *ship; // if (sc < 0) // return 0; if (ships == NULL || ships->selection == NULL) return 0; // wipe the selection clean ships->selection->numShips = 0; // check all ships in the damn universe node = universe.ShipList.head; while (node != NULL) { ship = (Ship *)listGetStructOfNode(node); if ((ship->flags & (SOF_Dead|SOF_Hide)) == 0) { // 1. is it an enemy? (simplifying assumption: "is it the human"?) // 2. is the right class? if (ship->playerowner->playerIndex == playerIndex && ship->staticinfo->shipclass == sc) // add it growSelectAddShip(ships, ship); } node = node->next; } return ships->selection->numShips; } // (enemy == human) sdword kasfFindEnemyShipsOfClass(GrowSelection *ships, char *shipClass) { return kasfFindPlayersShipsOfClass(ships, shipClass, 0); } // (friendly == not human) sdword kasfFindFriendlyShipsOfClass(GrowSelection *ships, char *shipClass) { return kasfFindPlayersShipsOfClass(ships, shipClass, 1); } sdword kasfPathNextPoint(void) { AITeamMove *thisMove = CurrentTeamP->curMove; if (CurrentTeamP->shipList.selection->numShips <= 0) return -1; if (!thisMove) { if (CurrentTeamP->moves.num > 0) thisMove = (AITeamMove *)listGetStructOfNode(CurrentTeamP->moves.tail); if (!thisMove) return -1; } if (thisMove->type == MOVE_PATROLMOVE) { if (thisMove->processing) // end of path or loop return 0; else return 1; // first point } if (thisMove->type != MOVE_MOVETEAMINDEX) return -1; // not patrolling a path return thisMove->params.move.index + 1; } // // PETER: I think we can nuke this now, right? // // // this is a placeholder for a real fleet intelligence message window // void kasfPopupTextDraw(void) { #if 1 sdword rowHeight, x, y, i, popupTextBorder; rectangle rect; fonthandle fhSave; //char buf[256]; if (!gameIsRunning || !popupTextNumLines) return; if (nisIsRunning) popupTextNumLines = 0; // set up textual stuff fhSave = fontCurrentGet(); //save the current font fontMakeCurrent(selGroupFont2); // use a common, fairly small font // to center it: x = 320 - popupTextWidth/2; //x = 640 - popupTextWidth - rowHeight*2; rowHeight = fontHeight("M") + 3; // used to space the text // to center it: y = (480 - (popupTextNumLines+2) * rowHeight) / 2; //y = rowHeight*2; popupTextBorder = rowHeight + 6; // border //primLineLoopStart2(1, POPUPTEXT_COLOR); //primLineLoopPoint3F(x - popupTextBorder, y - popupTextBorder); //primLineLoopPoint3F(x + popupTextWidth + popupTextBorder, y - popupTextBorder); //primLineLoopPoint3F(x + popupTextWidth + popupTextBorder, y + rowHeight * (popupTextNumLines+2) + popupTextBorder); //primLineLoopPoint3F(x - popupTextBorder, y + rowHeight * (popupTextNumLines+2) + popupTextBorder); //primLineLoopEnd2(); rect.x0 = x - popupTextBorder; rect.x1 = x + popupTextWidth + popupTextBorder; rect.y0 = y - popupTextBorder; rect.y1 = y + rowHeight * (popupTextNumLines+2) + popupTextBorder; primBeveledRectSolid(&rect, POPUPTEXT_BACKGROUND, 4, 4); primSeriesOfRoundRects(&rect, 1, POPUPTEXT_COLOR, POPUPTEXT_BORDER_COLOR, 5, 4, 4); // title fontPrint(x, y, POPUPTEXT_TITLE_COLOR, "FLEET INTELLIGENCE"); y += rowHeight*2; // each line of text for (i = 0; i < popupTextNumLines; i++) { fontPrint(x, y, POPUPTEXT_COLOR, popupTextLines[i]); y += rowHeight; } // stop displaying when expired if (universe.totaltimeelapsed > popupTextEndTime) popupTextNumLines = 0; fontMakeCurrent(fhSave); #endif #if 0 //sdword rowHeight, x, y, i, popupTextBorder; sdword i, width, x, y; bool done, justified; //rectangle rect; fonthandle fhSave; char *pos, *oldpos; char oldline[256], line[256]; //char buf[256]; if (!gameIsRunning || !popupTextNumLines) return; // set up textual stuff fhSave = fontCurrentGet(); //save the current font fontMakeCurrent(selGroupFont2); // use a common, fairly small font //x = 320 - popupTextWidth/2; //rowHeight = fontHeight("M") + 3; // used to space the text //y = (480 - (popupTextNumLines+2) * rowHeight) / 2; //popupTextBorder = rowHeight + 6; // border //primLineLoopStart2(1, POPUPTEXT_COLOR); //primLineLoopPoint3F(x - popupTextBorder, y - popupTextBorder); //primLineLoopPoint3F(x + popupTextWidth + popupTextBorder, y - popupTextBorder); //primLineLoopPoint3F(x + popupTextWidth + popupTextBorder, y + rowHeight * (popupTextNumLines+2) + popupTextBorder); //primLineLoopPoint3F(x - popupTextBorder, y + rowHeight * (popupTextNumLines+2) + popupTextBorder); //primLineLoopEnd2(); //rect.x0 = x - popupTextBorder; //rect.x1 = x + popupTextWidth + popupTextBorder; //rect.y0 = y - popupTextBorder; //rect.y1 = y + rowHeight * (popupTextNumLines+2) + popupTextBorder; //primBeveledRectSolid(&rect, POPUPTEXT_BACKGROUND, 4, 4); //primSeriesOfRoundRects(&rect, 1, POPUPTEXT_COLOR, POPUPTEXT_BORDER_COLOR, 5, 4, 4); // title //fontPrint(x, y, POPUPTEXT_TITLE_COLOR, "FLEET INTELLIGENCE"); //y += rowHeight*2; x = rect->x0; y = rect->y0; // each line of text for (i = 0; i < popupTextNumLines; i++) { //fontPrint(x, y, POPUPTEXT_COLOR, popupTextLines[i]); pos = popupTextLines[i]; done = FALSE; while (!done) { justified = FALSE; line[0]=0; while (!justified) { strcpy(oldline, line); oldpos = pos; pos = getWord(line, pos); if (pos[0] == '\n') { justified = TRUE; pos++; while ( pos[0] == ' ' ) pos++; } else { if ( (width=fontWidth(line)) > (rect->x1 - rect->x0)) { strcpy(line, oldline); pos = oldpos; while ( pos[0] == ' ' ) pos++; justified = TRUE; } if (pos[0]==0) { justified = TRUE; done = TRUE; } } } fontPrintf(x,y,POPUPTEXT_COLOR,"%s",line); y += fontHeight(" "); if (y > rect->y1 + fontHeight(" ")) done=TRUE; } //y += rowHeight; } // stop displaying when expired //if (universe.totaltimeelapsed > popupTextEndTime) // popupTextNumLines = 0; fontMakeCurrent(fhSave); #endif } // // PETER: I think we can nuke this now, right? // void kasfPopupText(char *line) { sdword width; fonthandle fhSave; if (popupTextNumLines >= POPUPTEXT_MAX_LINES) { strcpy(popupTextLines[POPUPTEXT_MAX_LINES-1], " - - message truncated - -"); return; } // set up textual stuff fhSave = fontCurrentGet(); //save the current font fontMakeCurrent(selGroupFont2); // use a common, fairly small font strncpy(popupTextLines[popupTextNumLines++], line, POPUPTEXT_MAX_LINE_LENGTH); width = fontWidth(popupTextLines[popupTextNumLines-1]); // set duration relative to number of lines if (popupTextNumLines == 1) { popupTextEndTime = universe.totaltimeelapsed; popupTextWidth = POPUPTEXT_BOX_WIDTH; } if (width > popupTextWidth) popupTextWidth = width; popupTextEndTime += POPUPTEXT_DURATION_PER_LINE; fontMakeCurrent(fhSave); } // // PETER: I think we can nuke this now, right? // void kasfPopupTextClear(void) { popupTextNumLines = 0; } // // new fleet-intelligence style popup // void kasfPopup(char *text) { fleetIntelligenceCreate(text, 1); } void kasfPopupInteger(char *text, sdword integer) { char tempstr[256]; // ensure not too long and that there is an integer field if (strlen(text) > 200 || !strstr(text, "%d")) return; sprintf(tempstr, text, integer); fleetIntelligenceCreate(tempstr, 1); } // // new fleet-intelligence style objectives & popup // void kasfObjectiveCreate(char *label, char *briefText, char *fullText) { if ((fullText == NULL) || (fullText[0] == 0)) { objectiveAndFleetIntelligenceCreate(label, briefText, briefText, 0, TRUE); } else { objectiveAndFleetIntelligenceCreate(label, briefText, fullText, 0, TRUE); } } void kasfObjectiveCreateSecondary(char* label, char* briefText, char* fullText) { if ((fullText == NULL) || (fullText[0] == 0)) { objectiveAndFleetIntelligenceCreate(label, briefText, briefText, 0, FALSE); } else { objectiveAndFleetIntelligenceCreate(label, briefText, fullText, 0, FALSE); } } void kasfObjectiveSet(char *label, sdword status) { objectiveSet(label, status); } //void kasfObjectivePopupAll(void) //{ // objectivePopupAll(); //} sdword kasfObjectiveGet(char *label) { return objectiveGet(label); } sdword kasfObjectiveGetAll(void) { return objectiveGetAll(); } void kasfObjectiveDestroy(char *label) { objectiveDestroy(label); } void kasfObjectiveDestroyAll(void) { objectiveDestroyAll(); } sdword kasfNISRunning(void) { return nisIsRunning; } sdword kasfShipsSelectEnemy(GrowSelection *newShips, GrowSelection *originalShips) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = !ship->playerowner->playerIndex; // enemy if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectFriendly(GrowSelection *newShips, GrowSelection *originalShips) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = ship->playerowner->playerIndex; // friendly if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectClass(GrowSelection *newShips, GrowSelection *originalShips, char *shipClass) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; ShipClass sc = StrToShipClass(shipClass); if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = isShipOfClass(ship, sc); // class matches if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectType(GrowSelection *newShips, GrowSelection *originalShips, char *shipType) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; ShipType st = StrToShipType(shipType); if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = (ship->shiptype == st); // class matches if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectCapital(GrowSelection *newShips, GrowSelection *originalShips) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = isCapitalShip(ship); // capital ship if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectNonCapital(GrowSelection *newShips, GrowSelection *originalShips) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = !isCapitalShip(ship); // non-capital ship if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectNotDocked(GrowSelection *newShips, GrowSelection *originalShips) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = ((ship->flags & (SOF_Hide | SOF_Hyperspace)) != SOF_Hide); // not docked if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectDamaged(GrowSelection *newShips, GrowSelection *originalShips, sdword maxHealthPercent) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = (ship->health <= maxHealthPercent * ship->staticinfo->maxhealth / 100); // low health if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectMoving(GrowSelection *newShips, GrowSelection *originalShips) { Ship *ship; sdword i, selected, sourceIsDest = FALSE; if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; if (newShips == originalShips) sourceIsDest = TRUE; else // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // find all originalShips that satisfy the selection criteria to newShips for (i = 0; i < originalShips->selection->numShips; ++i) { ship = originalShips->selection->ShipPtr[i]; selected = ship->posinfo.isMoving & ISMOVING_MOVING; // moving if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } sdword kasfShipsSelectIndex(GrowSelection *newShips, GrowSelection *originalShips, sdword Index) { if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; // start with empty new selection while (newShips->selection->numShips) clRemoveShipFromSelection(newShips->selection, newShips->selection->ShipPtr[0]); // if index is larger than the numships, or if numships is zero // return 0 if ((originalShips->selection->numShips <= Index) || (!originalShips->selection->numShips)) { return 0; } newShips->selection->ShipPtr[0] = originalShips->selection->ShipPtr[Index]; newShips->selection->numShips = 1; return 1; } // selects the ships in originalShips that are within distance of location sdword kasfShipsSelectNearby(GrowSelection *newShips, GrowSelection *originalShips, hvector *location, sdword distance) { Ship *ship; real32 rangeSquared = (real32)distance*(real32)distance; sdword i; vector loc; vecGrabVecFromHVec(loc,*location); if (newShips == NULL || newShips->selection == NULL || originalShips == NULL || originalShips->selection == NULL) return 0; // wipe the selection clean newShips->selection->numShips = 0; // add any ships close to the location to the newShips shiplist for (i=0;iselection->numShips;i++) { ship = originalShips->selection->ShipPtr[i]; if (aiuFindDistanceSquared(ship->posinfo.position,loc) < rangeSquared) { growSelectAddShip(newShips, ship); } } return newShips->selection->numShips; } //local function /*----------------------------------------------------------------------------- Name : kasfShipsMeetsCriteria Description : Returns TRUE if the ship meets the criteria determined by the CriteriaFlag Inputs : ship - the ship being tested, CriteriaFlag - the criteria to test Outputs : Return : TRUE if the ship meets the criteria ----------------------------------------------------------------------------*/ bool kasfShipMeetsCriteria(ShipPtr ship, sdword CriteriaFlag) { switch (CriteriaFlag) { case kasSpecial_ReturningTechnology: if ((ship->shiptype == SalCapCorvette) && (bitTest(ship->specialFlags, SPECIAL_SalvageTakingHomeTechnology))) return TRUE; break; case kasSpecial_ShipsDisabled: if (bitTest(ship->flags, SOF_Disabled)) return TRUE; break; case kasSpecial_ShipsAreArmed: switch (ship->staticinfo->shipclass) { case CLASS_Fighter: case CLASS_HeavyCruiser: case CLASS_Carrier: case CLASS_Destroyer: return TRUE; break; case CLASS_Frigate: switch (ship->shiptype) { case CloakGenerator: case ResourceController: return FALSE; default: return TRUE; } break; case CLASS_Corvette: switch (ship->shiptype) { case RepairCorvette: case SalCapCorvette: return FALSE; default: return TRUE; } break; default: return FALSE; } case kasSpecial_ShipsDefected: if (bitTest(ship->attributes, ATTRIBUTES_Defector)) return TRUE; break; default: return FALSE; } return FALSE; } /*----------------------------------------------------------------------------- Name : kasfShipsSelectSpecial Description : Selects the ships using different criteria depending on the SpecialFlag setting Inputs : newShips - pointer to growselection (pass by reference) originalShips - the ships to filter SpecialFlag - indicates the criteria Outputs : Return : The number of ships selected ----------------------------------------------------------------------------*/ sdword kasfShipsSelectSpecial(GrowSelection *newShips, GrowSelection *originalShips, sdword SpecialFlag) { ShipPtr ship; bool selected = FALSE, sourceIsDest = FALSE; udword i; if ((newShips == NULL) || (newShips->selection == NULL) || (originalShips == NULL) || (originalShips->selection == NULL)) { return 0; } if (newShips == originalShips) sourceIsDest = TRUE; else //start with an empty new selection newShips->selection->numShips = 0; for (i=0; i < originalShips->selection->numShips; i++) { ship = originalShips->selection->ShipPtr[i]; selected = kasfShipMeetsCriteria(ship, SpecialFlag); if (!selected && sourceIsDest) // remove from source (dest) clRemoveShipFromSelection(originalShips->selection, ship); else if (selected && !sourceIsDest) // add to dest growSelectAddShip(newShips, ship); } return newShips->selection->numShips; } // // A = A + B // sdword kasfShipsAdd(GrowSelection *shipsA, GrowSelection *shipsB) { sdword i; if (shipsA == NULL || shipsA->selection == NULL || shipsB == NULL || shipsB->selection == NULL) return 0; if (shipsA == shipsB) return shipsA->selection->numShips; for (i = 0; i < shipsB->selection->numShips; ++i) growSelectAddShipNoDuplication(shipsA, shipsB->selection->ShipPtr[i]); return shipsA->selection->numShips; } // // A = A - B // sdword kasfShipsRemove(GrowSelection *shipsA, GrowSelection *shipsB) { sdword i; if (shipsA == NULL || shipsA->selection == NULL || shipsB == NULL || shipsB->selection == NULL) return 0; if (shipsA == shipsB) { while (shipsA->selection->numShips) clRemoveShipFromSelection(shipsA->selection, shipsA->selection->ShipPtr[0]); return 0; } for (i = 0; i < shipsB->selection->numShips; ++i) growSelectRemoveShip(shipsA, shipsB->selection->ShipPtr[i]); return shipsA->selection->numShips; } //returns TRUE if all the selected ships are in the specified formation sdword kasfSelectedShipsInFormation(sdword formation) { udword i; if (!selSelected.numShips) { return FALSE; } for (i=0;iformationcommand || (selSelected.ShipPtr[i]->formationcommand->formation.formationtype != (TypeOfFormation)formation)) { return FALSE; } } return TRUE; } //returns TRUE if any of the ships are in the specific formation sdword kasfShipsInFormation(GrowSelection *ships, sdword formation) { udword i; if (formation == -1) { for (i=0;iselection->numShips;i++) { if (ships->selection->ShipPtr[i]->formationcommand) { return TRUE; } } } else { for (i=0;iselection->numShips;i++) { if (ships->selection->ShipPtr[i]->formationcommand && (ships->selection->ShipPtr[i]->formationcommand->formation.formationtype == (TypeOfFormation)formation)) { return TRUE; } } } return FALSE; } // // sets the ships so that the player's ships don't autoretaliate against them // void kasfShipsSetNonRetaliation(GrowSelection *ships) { udword i; for (i=0;iselection->numShips;i++) { bitSet(ships->selection->ShipPtr[i]->specialFlags, SPECIAL_FriendlyStatus); } } // // sets the ships so that the player's ships don't autoretaliate against them // void kasfShipsSetRetaliation(GrowSelection *ships) { udword i; for (i=0;iselection->numShips;i++) { bitClear(ships->selection->ShipPtr[i]->specialFlags, SPECIAL_FriendlyStatus); } } /*----------------------------------------------------------------------------- Name : kasfPingAddSingleShip Description : Add a ping for a single ship, the first in the selection Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfPingAddSingleShip(GrowSelection *ships, char *label) { if (ships == NULL || ships->selection == NULL || ships->selection->ShipPtr[0] == NULL) return; pingAnomalyObjectPingAdd(label, (SpaceObj *)(ships->selection->ShipPtr[0])); } /*----------------------------------------------------------------------------- Name : kasfPingAddShips Description : Add a ping for a group of ships. The ping will be centred about the entire group of ships. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfPingAddShips(GrowSelection *ships, char *label) { if (ships == NULL || ships->selection == NULL || ships->selection->ShipPtr[0] == NULL) return; pingAnomalySelectionPingAdd(label, ships->selection); } void kasfPingAddPoint(hvector *point, char *label) { pingAnomalyPositionPingAdd(label, (vector *)point); } void kasfPingRemove(char *label) { pingAnomalyPingRemove(label); } void kasfStop(void) { aitDeleteAllTeamMoves(CurrentTeamP); clWrapHalt(&universe.mainCommandLayer, CurrentTeamP->shipList.selection); } void kasfHarvest(void) { MaxSelection tempSelection; SelectCommand *selection = CurrentTeamP->shipList.selection; //aitDeleteAllTeamMoves(CurrentTeamP); if (selection->numShips > 0) { if (MakeShipsHarvestCapable((SelectCommand *)&tempSelection, selection)) { clWrapCollectResource(&universe.mainCommandLayer,(SelectCommand *)&tempSelection,NULL); } } } void kasfBuildControl(sdword on) { singlePlayerGameInfo.giveComputerFleetControl = on; } // sets the team as a building team for the KAS script void kasfBuildingTeam(struct AITeam *builder) { //for now, just set the first ship on the team (assume it only has one ship) aiCurrentAIPlayer->ScriptCreator = builder->shipList.selection->ShipPtr[0]; } void kasfKamikaze(GrowSelection *targets) { // alloc memory that the move can later free itself SelectCommand *dupeTargets = selectDupSelection(targets->selection); if (dupeTargets->numShips && dupeTargets->ShipPtr[0] != NULL) { aitDeleteAllTeamMoves(CurrentTeamP); aimCreateKamikaze(CurrentTeamP, dupeTargets, SAME_FORMATION, FALSE, TRUE); } } void kasfKamikazeEveryone(GrowSelection *targets) { AITeam *teamp; udword i; if (targets->selection->numShips && targets->selection->ShipPtr[0] != NULL) { for (i = 0; i < aiCurrentAIPlayer->teamsUsed; i++) { teamp = aiCurrentAIPlayer->teams[i]; if (teamp->shipList.selection->numShips) { aitDeleteAllTeamMoves(teamp); aimCreateKamikaze(teamp, selectDupSelection(targets->selection), SAME_FORMATION, FALSE, TRUE); } } } } void kasfSpecialToggle(void) { real32 maxHealth = 0.0, actualHealth = 0.0; if (!CurrentTeamP || !CurrentTeamP->shipList.selection->numShips) return; clWrapSpecial(&universe.mainCommandLayer, CurrentTeamP->shipList.selection, NULL); } void kasfShipsDamage(GrowSelection *ships, sdword points) { sdword i; if (ships == NULL || ships->selection == NULL) return; for (i = 0; i < ships->selection->numShips; ++i) ApplyDamageToTarget((struct SpaceObjRotImpTarg *)ships->selection->ShipPtr[i], (real32)points, 0, 0, 0); } void kasfForceTaskbar() { tbForceTaskbar(TRUE); } /* ---------------------------------------------------------------------------- The following functions have been added to facilitate the tutorial mission. ---------------------------------------------------------------------------- */ void kasfBuilderRestrictShipTypes(char *shipTypes) { tutBuilderSetRestrictions(shipTypes, 1); } void kasfBuilderUnrestrictShipTypes(char *shipTypes) { tutBuilderSetRestrictions(shipTypes, 0); } void kasfBuilderRestrictAll(void) { tutBuilderRestrictAll(); } void kasfBuilderRestrictNone(void) { tutBuilderRestrictNone(); } void kasfBuilderCloseIfOpen(void) { cmCloseIfOpen(); } // figure out how to do this someday.... void kasfForceBuildShipType(char *shipType) { ShipType st; st = StrToShipType(shipType); cmForceBuildShipType(st); // clWrapBuildShip(&universe.mainCommandLayer,st,universe.curPlayerPtr->race,0,universe.curPlayerPtr->PlayerMothership); } // Range from 0 to 359 as universe moves from right to left sdword kasfCameraGetAngleDeg(void) { return (sdword)RAD_TO_DEG(currentCameraStackEntry(&universe.mainCameraCommand)->remembercam.angle); } // Range from -90 (Above) to +90 (Below) sdword kasfCameraGetDeclinationDeg(void) { return (sdword)RAD_TO_DEG(currentCameraStackEntry(&universe.mainCameraCommand)->remembercam.declination); } sdword kasfCameraGetDistance(void) { return (sdword)currentCameraStackEntry(&universe.mainCameraCommand)->remembercam.distance; } sdword kasfSelectNumSelected(void) { return selSelected.numShips; } sdword kasfSelectIsSelectionShipType(sdword Index, char *shipType) { ShipType st; st = StrToShipType(shipType); return ((selSelected.numShips > Index) && selSelected.ShipPtr[Index]->shiptype == st); } sdword kasfSelectContainsShipTypes(char *shipTypes) { return tutSelectedContainsShipTypes(shipTypes); } void kasfTutSetPointerTargetXY(char *name, sdword x, sdword y) { tutSetPointerTargetXY(name, x,y); } void kasfTutSetPointerTargetXYRight(char *name, sdword x, sdword y) { tutSetPointerTargetXYRight(name, x,y); } void kasfTutSetPointerTargetXYBottomRight(char *name, sdword x, sdword y) { tutSetPointerTargetXYBottomRight(name, x,y); } void kasfTutSetPointerTargetXYTaskbar(char *name, sdword x, sdword y) { tutSetPointerTargetXYTaskbar(name, x,y); } void kasfTutSetPointerTargetXYFE(char *name, sdword x, sdword y) { tutSetPointerTargetXYFE(name, x,y); } void kasfTutSetPointerTargetShip(char *name, GrowSelection *ships) { if(ships->selection->numShips > 0) { tutSetPointerTargetShip(name, ships->selection->ShipPtr[0]); } } void kasfTutSetPointerTargetShipSelection(char *name, GrowSelection *ships) { if(ships->selection->numShips > 0) { tutSetPointerTargetShipSelection(name, ships->selection); } } void kasfTutSetPointerTargetShipHealth(char *name, GrowSelection *ships) { if(ships->selection->numShips > 0) tutSetPointerTargetShipHealth(name, ships->selection->ShipPtr[0]); } void kasfTutSetPointerTargetShipGroup(char *name, GrowSelection *ships) { if(ships->selection->numShips > 0) { tutSetPointerTargetShipGroup(name, ships->selection->ShipPtr[0]); } } void kasfTutSetPointerTargetFERegion(char *name, char *pAtomName) { tutSetPointerTargetFERegion(name, pAtomName); } void kasfTutSetPointerTargetRect(char *name, sdword x0, sdword y0, sdword x1, sdword y1) { tutSetPointerTargetRect(name, x0, y0, x1, y1); } void kasfTutSetPointerTargetAIVolume(char *name, Volume *volume) { tutSetPointerTargetAIVolume(name, volume); } void kasfTutRemovePointer(char *name) { tutRemovePointerByName(name); } void kasfTutRemoveAllPointers(void) { tutRemoveAllPointers(); } void kasfTutSetTextDisplayBoxGame(sdword x, sdword y, sdword width, sdword height) { tutSetTextDisplayBox(x, y, width, height, TRUE); } void kasfTutSetTextDisplayBoxToSubtitleRegion(void) { tutSetTextDisplayBoxToSubtitleRegion(); } void kasfTutSetTextDisplayBoxFE(sdword x, sdword y, sdword width, sdword height) { tutSetTextDisplayBox(x, y, width, height, FALSE); } void kasfTutShowText(char *szText) { tutShowText(szText); } void kasfTutHideText(void) { tutHideText(); } void kasfTutShowNextButton(void) { tutShowNextButton(); } void kasfTutHideNextButton(void) { tutHideNextButton(); } sdword kasfTutNextButtonClicked(void) { return tutNextButtonClicked(); } void kasfTutShowBackButton(void) { tutShowBackButton(); } void kasfTutHideBackButton(void) { tutHideBackButton(); } void kasfTutShowPrevButton(void) { tutShowPrevButton(); } void kasfTutSaveLesson(sdword Num, char *pName) { tutSaveLesson(Num, pName); } void kasfTutShowImages(char *szImages) { tutShowImages(szImages); } void kasfTutHideImages(void) { tutHideImages(); } void kasfTutEnableEverything(void) { tutEnableEverything(); } void kasfTutDisableEverything(void) { tutDisableEverything(); } void kasfTutEnableFlags(char *pFlags) { tutSetEnableFlags(pFlags, 1); } void kasfTutDisableFlags(char *pFlags) { tutSetEnableFlags(pFlags, 0); } void kasfTutForceUnpaused(void) { universePause = FALSE; } sdword kasfTutGameSentMessage(char *commandNames) { return tutGameSentMessage(commandNames); } void kasfTutResetGameMessageQueue(void) { tutResetGameMessageQueue(); } sdword kasfTutContextMenuDisplayedForShipType(char *shipType) { return tutContextMenuDisplayedForShipType(shipType); } void kasfTutResetContextMenuShipTypeTest(void) { tutResetContextMenuShipTypeTest(); } void kasfTutRedrawEverything(void) { bitSet(regRootRegion.status, RSF_ReallyDirty); } sdword kasfBuildManagerShipTypeInBatchQueue(char *shipType) { return tutBuildManagerShipTypeInBatchQueue(shipType); } sdword kasfBuildManagerShipTypeInBuildQueue(char *shipType) { return tutBuildManagerShipTypeInBuildQueue(shipType); } sdword kasfBuildManagerShipTypeSelected(char *shipType) { return tutBuildManagerShipTypeSelected(shipType); } sdword kasfTutCameraFocusedOnShipType(char *shipTypes) { return tutCameraFocusedOnShipType(shipTypes); } void kasfTutCameraFocus(GrowSelection *ships) { if(ships->selection->numShips > 0) { ccCameraTimeoutOverride = TRUE; // go to a clean main screen if (piePointSpecMode != PSM_Idle) { piePointModeOnOff(); } spMainScreen(); ccFocus(&universe.mainCameraCommand, (FocusCommand *)ships->selection); } else { //if ships has no ships, focus on selselected MaxSelection tempselected; tutGameMessage("KB_Focus"); tempselected = selSelected; //copy structure MakeShipMastersIncludeSlaves((SelectCommand *)&tempselected); ccFocus(&universe.mainCameraCommand,(FocusCommand *)&tempselected); } } void kasfTutCameraFocusDerelictType(char *derelictType) { Derelict *derelict; Node *node; DerelictSelection focus; DerelictType dt = StrToDerelictType(derelictType); focus.numDerelicts = 1; // go through the entire list of derelicts node = universe.DerelictList.head; while (node != NULL) { derelict = (Derelict *)listGetStructOfNode(node); if (derelict->derelicttype == dt) { ccCameraTimeoutOverride = TRUE; // go to a clean main screen if (piePointSpecMode != PSM_Idle) { piePointModeOnOff(); } spMainScreen(); focus.DerelictPtr[0] = derelict; ccFocus(&universe.mainCameraCommand, (FocusCommand *)&focus); return; } node = node->next; } } void kasfTutCameraFocusFar(GrowSelection *ships) { if (ships->selection->numShips > 0) { spMainScreen(); ccCameraTimeoutOverride = TRUE; ccFocusFar(&universe.mainCameraCommand, (FocusCommand *)ships->selection, &universe.mainCameraCommand.actualcamera); } else { //if ships has no ships, focus on selselected MaxSelection tempselected; tutGameMessage("KB_Focus"); tempselected = selSelected; //copy structure MakeShipMastersIncludeSlaves((SelectCommand *)&tempselected); ccFocusFar(&universe.mainCameraCommand,(FocusCommand *)&tempselected, &universe.mainCameraCommand.actualcamera); } } void kasfTutCameraFocusCancel(void) { ccCameraTimeoutOverride = FALSE; ccCancelFocus(&universe.mainCameraCommand); } /*----------------------------------------------------------------------------- Name : kasfDisablePlayer Description : Disables player commands Inputs : toggle - if TRUE the player's commands gets disabled, if FALSE, the player's commands get enabled Outputs : Return : void ----------------------------------------------------------------------------*/ void kasfDisablePlayer(bool toggle) { if (toggle) { mrDisable(); } else { mrEnable(); } } sdword kasfTutShipsInView(GrowSelection *ships) { udword i, inview = 0; for (i=0;iselection->numShips;i++) { if (rndShipVisible((SpaceObj *)ships->selection->ShipPtr[i], mrCamera)) { inview++; } } return inview; } sdword kasfTutShipsTactics(GrowSelection *ships) { if (ships->selection->numShips) return ships->selection->ShipPtr[0]->tacticstype; else return -1; } sdword kasfTutPieDistance(void) { extern real32 pieDistance; return (sdword)pieDistance; } sdword kasfTutPieHeight(void) { extern real32 pieHeight; return (sdword)pieHeight; } void kasfForceFISensors(void) { smFleetIntel = TRUE; } void kasfOpenSensors(sdword flag) { #if UNIVERSE_TURBOPAUSE_DEBUG universeTurbo = FALSE; #endif //if flag isn't a TRUE/FALSE value //note: opening the sensors manager at a given distance only // requires the "flag" variable to be larger than 1000 or // so. If need be, values above 1 can be used to flag // different cases if (flag > 1) { //store the sensors manager zoom length kasStoreSMInitialDistance = (sdword)smInitialDistance; //set the sensors manager zoom length smInitialDistance = (real32)flag; smFleetIntel = TRUE; } else { smFleetIntel = flag; } spMainScreen(); smSensorsBegin(NULL, NULL); } void kasfCloseSensors(sdword flag) { /* #ifdef gshaw if (smFleetIntel != TRUE) { return; } #endif dbgAssert(smFleetIntel==TRUE); */ if ((smSensorsActive) && (!smZoomingIn) && (!smZoomingOut)) { if (kasStoreSMInitialDistance) { //restore the sensors manager zoom length smInitialDistance = (real32)kasStoreSMInitialDistance; kasStoreSMInitialDistance = 0; } //flags don't do anything yet smSensorsClose(NULL, NULL); smFleetIntel = FALSE; } } sdword kasfSensorsIsOpen(sdword flag) { if (flag) { //returns true if the fleet intel window is open return smFleetIntel; } else { //returns true if the player is in the sensors manager but not fleet intel return ((smSensorsActive || smZoomingIn || smZoomingOut) && !smFleetIntel); } } void kasfSensorsWeirdness(sdword value) { // static nisstatic stat2; // static nisstatic stat3; smSensorWeirdness = value; /* if (flag) { stat1.index = 0; nisStaticOnExp(&stat1); // nisStaticOnExp(&stat2); // nisStaticOnExp(&stat3); smSensorWeirdnessInit(); } else { nisStaticOffExp(0); // nisStaticOffExp(1); // nisStaticOffExp(2); } */ } void kasfAllowPlayerToResearch(char *name) { AllowPlayerToResearch(name); } void kasfAllowPlayerToPurchase(char *name) { AllowPlayerToPurchase(name); } void kasfPlayerAcquiredTechnology(char *name) { PlayerAcquiredTechnology(name); } sdword kasfCanPlayerResearch(char *name) { return CanPlayerResearch(name); } sdword kasfCanPlayerPurchase(char *name) { return CanPlayerPurchase(name); } sdword kasfDoesPlayerHave(char *name) { return DoesPlayerHave(name); } void kasfSetBaseTechnologyCost(char *name, sdword cost) { SetBaseTechnologyCost(name, cost); } sdword kasfGetBaseTechnologyCost(char *name) { return GetBaseTechnologyCost(name); } sdword kasfTechIsResearching(void) { return rmResearchingAnything(&universe.players[0]); } void kasfEnableTraderGUI(void) { tmEnableTraderGUI(); } sdword kasfTraderGUIActive(void) { return tmTraderGUIActive(); } void kasfSetTraderDialog(sdword dialogNum, char *text) { tmSetDialog(dialogNum, text); } void kasfSetTraderPriceScale(sdword percent) { tmSetPriceScale(percent); } void kasfSetTraderDisabled(sdword disable) { tmSetTradeDisabled(disable); } sdword kasfGetTraderPriceScale(void) { return tmGetPriceScale(); } sdword kasfRUsGet(sdword player) { return universe.players[player].resourceUnits; } void kasfRUsSet(sdword player, sdword RUs) { universe.players[player].resourceUnits = RUs; } sdword kasfGetWorldResources(void) { sdword total, numHarvestables, numAsteroid0s; univGetResourceStatistics(&total, &numHarvestables, &numAsteroid0s); return total; } void kasfSoundEvent(sdword event) { soundEventMisc(event); } void kasfSoundEventShips(GrowSelection *ships, sdword event) { if (ships == NULL || ships->selection == NULL || ships->selection->numShips == 0) return; soundEvent(ships->selection->ShipPtr[0], event); } void kasfSpeechEvent(sdword event, sdword variable) { subMessageEnded = 0; speechEventFleet(event, variable, universe.curPlayerIndex); } void kasfSpeechEventShips(GrowSelection *ships, sdword event, sdword variable) { if (ships == NULL || ships->selection == NULL || ships->selection->numShips == 0) return; speechEvent(ships->selection->ShipPtr[0], event, variable); } void kasfToggleActor(sdword Actor, sdword on) { soundEventSetActorFlag(Actor, on); } void kasfMusicPlay(sdword trackNum) { soundEventPlayMusic((udword)trackNum); } void kasfMusicStop(sdword fadeTime) { soundEventStopMusic((real32)fadeTime); } sdword kasfRenderedShips(GrowSelection *ships, sdword LOD) { sdword i; ubyte LODmask; for (LODmask = 0, i = 8; i > 0; i--) { //prepare a mask for the given LOD if (i <= LOD) { LODmask |= 1; } LODmask <<= 1; } if (ships == NULL || ships->selection == NULL) return 0; for (i = 0; i < ships->selection->numShips; ++i) //see if ship rendered at the specified LOD or lower { if (bitTest(ships->selection->ShipPtr[i]->renderedLODs, LODmask)) { return 1; } } return 0; } void kasfResetShipRenderFlags(GrowSelection *ships) { sdword i; if (ships == NULL || ships->selection == NULL) return; for (i=0; i < ships->selection->numShips; i++) ships->selection->ShipPtr[i]->renderedLODs = 0; } sdword kasfRenderedDerelicts(char *derelictType, sdword LOD) { Derelict *derelict; Node *node; DerelictType dt = StrToDerelictType(derelictType); // go through the entire list of derelicts node = universe.DerelictList.head; while (node != NULL) { derelict = (Derelict *)listGetStructOfNode(node); if ((derelict->derelicttype == dt) && bitTest(derelict->renderedLODs, 1 << LOD)) return 1; node = node->next; } return 0; } void kasfResetDerelictRenderFlags(char *derelictType) { Derelict *derelict; Node *node; DerelictType dt = StrToDerelictType(derelictType); // go through the entire list of derelicts node = universe.DerelictList.head; while (node != NULL) { derelict = (Derelict *)listGetStructOfNode(node); if (derelict->derelicttype == dt) { derelict->renderedLODs = 0; break; } node = node->next; } } void kasfGateMoveToNearest(void) { real32 temp; real32 closestDistSquared = -1; sdword i; vector loc; vector shippos; SelectCommand *selection = CurrentTeamP->shipList.selection; Derelict *gate = NULL; Derelict *closest = NULL; if (selection == NULL || !selection->numShips) return; shippos = selection->ShipPtr[0]->posinfo.position; for (i = 0; i < LabelledVectorsUsed; ++i) { if (!strnicmp(LabelledVectors[i]->label, "GATE", 4)) { vecGrabVecFromHVec(loc, *(LabelledVectors[i]->hvector)); temp = aiuFindDistanceSquared(shippos,loc); if (closestDistSquared == -1 || temp <= closestDistSquared) { if ((gate = GetHyperspaceGateFromVector(&loc)) != NULL) { closestDistSquared = temp; closest = gate; } } } } if (closestDistSquared != -1 && closest) { // we now have a pointer to the hyperspace gate derelict vector shipToGate; vector gateNormal; vector waypoint; vector gatePosition; gatePosition = closest->posinfo.position; vecSub(shipToGate,gatePosition,shippos); matGetVectFromMatrixCol3(gateNormal,closest->rotinfo.coordsys); if (vecDotProduct(shipToGate,gateNormal) > 0.0f) { // shipToGate and gateNormal are pointing in same direction...pick back direction; vecNegate(gateNormal); } vecMultiplyByScalar(gateNormal,HYPERSPACEGATE_WAYPOINTDIST); vecAdd(waypoint,gateNormal,gatePosition); aitDeleteAllTeamMoves(CurrentTeamP); aimCreateMoveTeam(CurrentTeamP, waypoint, SAME_FORMATION, TRUE, TRUE); aimCreateMoveTeam(CurrentTeamP, gatePosition, SAME_FORMATION, TRUE, TRUE); } } void kasfGateDestroy(hvector *gatePoint) { //hyperspace hsStaticDestroy(gatePoint); } void kasfGateShipsIn(GrowSelection *ships, hvector *gatePoint) { //hyperspace spHyperspaceSelectionInStatic(ships->selection, gatePoint); } void kasfGateShipsOut(GrowSelection *ships, hvector *gatePoint) { //hyperspace RemoveShipsFromDoingStuff(&universe.mainCommandLayer,ships->selection); spHyperspaceSelectionOutStatic(ships->selection); } sdword kasfGateShipsOutNearest(GrowSelection *ships) { hvector *closest = NULL; real32 temp; real32 closestDistSquared = -1; sdword i; vector loc; SelectCommand *selection; selection = ships->selection; if (selection == NULL || !selection->numShips) return 0; for (i = 0; i < LabelledVectorsUsed; ++i) { if (!strnicmp(LabelledVectors[i]->label, "GATE", 4)) { vecGrabVecFromHVec(loc, *(LabelledVectors[i]->hvector)); temp = aiuFindDistanceSquared( selection->ShipPtr[0]->posinfo.position, loc); if (closestDistSquared == -1 || temp <= closestDistSquared) { closestDistSquared = temp; closest = LabelledVectors[i]->hvector; } } } if (closestDistSquared != -1 && closest) { if (closestDistSquared < 4000000) { RemoveShipsFromDoingStuff(&universe.mainCommandLayer,selection); spHyperspaceSelectionOutStatic(selection); return TRUE; } } return FALSE; } //creates a list of the player's currently selected ships //added for the tutorial udword kasfFindSelectedShips(GrowSelection *ships) { udword i; if (ships == NULL) return 0; while (ships->selection->numShips) clRemoveShipFromSelection(ships->selection, ships->selection->ShipPtr[0]); for (i=0;iselection->numShips; ++i) { if (bitTest(ships->selection->ShipPtr[i]->flags, SOF_Disabled)) ++count; } return count; } //saves a single player level void kasfSaveLevel(sdword LevelNum, char *LevelName) { // char levelName[256]; //LM:Why is this here? It trips an assertion... btgSetColourMultiplier(-1.0f); collUpdateCollBlobs(); collUpdateObjsInCollBlobs(); sprintf(CurrentLevelName, "%s%s", SinglePlayerSavedGamesPath, LevelName); if (SaveGame(CurrentLevelName)) clCommandMessage(strGetString(strSavedGame)); else clCommandMessage(strGetString(strPatchUnableWriteFile)); } /*----------------------------------------------------------------------------- Name : kasfClearScreen Description : Refreshes the screen Inputs : none Outputs : the player's monitor feels a clearing sensation Return : void ----------------------------------------------------------------------------*/ void kasfClearScreen(void) { rndClear(); } //starts the NIS widescreen thing under KAS control void kasfWideScreenIn(sdword frames) { #if UNIVERSE_TURBOPAUSE_DEBUG universeTurbo = FALSE; #endif dbgAssert(frames > 1 && frames < 10000); if (nisScissorFadeOut != 0) { nisScissorFade = nisScissorFadeOut = nisScissorFadeTime = 0.0f; } soundEvent(NULL, UI_Letterbox); nisScissorFadeIn = (real32)frames / NIS_FrameRate; nisTaskResume(); } //ends the NIS widescreen thing under KAS control void kasfWideScreenOut(sdword frames) { dbgAssert(frames > 1 && frames < 10000); if (nisScissorFadeIn != 0) { nisScissorFade = nisScissorFadeIn = nisScissorFadeTime = 0.0f; } soundEvent(NULL, UI_Unletterbox); nisScissorFadeOut = (real32)frames / NIS_FrameRate; nisTaskResume(); } //simulate a subtitle static sdword kasfDummyEventNumber = 0; //incremented to ensure uniquie event numbers void kasfSubtitleSimulate(sdword actor, sdword milliseconds, char *speech) { dbgAssert(milliseconds > 10); subTitleAdd(actor, kasfDummyEventNumber, speech, strlen(speech), (real32)milliseconds / 1000.0f); subMessageEnded = 0; kasfDummyEventNumber++; } //display a location card void kasfLocationCard(sdword milliseconds, char *location) { char buffer[SUB_SubtitleLength]; dbgAssert(milliseconds > 10); _snprintf(buffer, SUB_SubtitleLength - 1, "#r%x#t%x%s", STR_LocationCard, STT_LocationCard, location); subTitleAdd(STA_LocationCard, kasfDummyEventNumber, buffer, strlen(buffer), (real32)milliseconds / 1000.0f); kasfDummyEventNumber++; } //display easter egg location card void kasfLocationCardSpecial(sdword milliseconds, char *string) { // char buffer[SUB_SubtitleLength]; dbgAssert(milliseconds > 10); subTitleAdd(STA_LocationCard, kasfDummyEventNumber, string, strlen(string), (real32)milliseconds / 1000.0f); kasfDummyEventNumber++; } sdword kasfRaceOfHuman(void) { return universe.players[0].race; } //hides some ships and sets the SOF_HideSave bit where appropriate so the NIS can unhide them void kasfHideShips(GrowSelection *ships) { sdword index; for (index = 0; index < ships->selection->numShips; index++) { if (bitTest(ships->selection->ShipPtr[index]->flags, SOF_Hide)) { //if ship already hidden bitSet(ships->selection->ShipPtr[index]->flags, SOF_HideSave); } else { univRemoveObjFromRenderList((SpaceObj *)ships->selection->ShipPtr[index]); bitSet(ships->selection->ShipPtr[index]->flags, SOF_Hide); } } } //unhides some ships and sets the SOF_HideSave bit where appropriate so the NIS can unhide them void kasfUnhideShips(GrowSelection *ships) { sdword index; for (index = 0; index < ships->selection->numShips; index++) { if (bitTest(ships->selection->ShipPtr[index]->flags, SOF_HideSave)) { //if ship was hidden to begin with bitClear(ships->selection->ShipPtr[index]->flags, SOF_HideSave); } else { bitClear(ships->selection->ShipPtr[index]->flags, SOF_Hide); } } } /*----------------------------------------------------------------------------- Name : kasfDeleteShips Description : Deletes a select of ships from the game Inputs : ships - the ships to delete Outputs : wipes the ships from the game Return : void ----------------------------------------------------------------------------*/ void kasfDeleteShips(GrowSelection *ships) { while (ships->selection->numShips) { univWipeShipOutOfExistence(ships->selection->ShipPtr[0]); } } /*----------------------------------------------------------------------------- Name : kasfRotateDerelictType Description : Rotates a type of derelict Inputs : derelictType - string of derelict type rot_x - rotation speed around x axis (*1000) rot_y - rotation speed around y axis (*1000) rot_z - rotation speed around z axis (*1000) variation - amount of random rotation variation Outputs : Return : void ----------------------------------------------------------------------------*/ void kasfRotateDerelictType(char *derelictType, sdword rot_x, sdword rot_y, sdword rot_z, sdword variation) { Derelict *derelict; Node *node; DerelictType dt = StrToDerelictType(derelictType); real32 realrot_x = (real32)rot_x, realrot_y = (real32)rot_y, realrot_z = (real32)rot_z, realvariation = (real32)variation; // scale rotation values to their proper values realrot_x /= 1000; realrot_y /= 1000; realrot_z /= 1000; realvariation /= 1000; //go through the entire list of derelicts and //give the appropriate ones a rotation node = universe.DerelictList.head; while (node != NULL) { derelict = (Derelict *)listGetStructOfNode(node); if (derelict->derelicttype == dt) { derelict->rotinfo.rotspeed.x = realrot_x + frandyrandombetween(RAN_AIPlayer, -realvariation, realvariation); derelict->rotinfo.rotspeed.y = realrot_y + frandyrandombetween(RAN_AIPlayer, -realvariation, realvariation); derelict->rotinfo.rotspeed.z = realrot_z + frandyrandombetween(RAN_AIPlayer, -realvariation, realvariation); } node = node->next; } } /*----------------------------------------------------------------------------- Name : kasfUniversePause Description : Pause all ships in the universe Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfUniversePause(void) { nisUniversePause = TRUE; #if NIS_VERBOSE_LEVEL >= 1 dbgMessage("\nKAS has PAUSED the universe."); #endif //!!! pause KAS timers and FSM's } /*----------------------------------------------------------------------------- Name : kasfUniverseUnpause Description : Pause all ships in the universe Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfUniverseUnpause(void) { nisUniversePause = FALSE; #if NIS_VERBOSE_LEVEL >= 1 dbgMessage("\nKAS has UNPAUSED the universe."); #endif //!!! unpause KAS timers and FSM's } // pause the build void kasfPauseBuildShips(void) { cmPauseAllJbos(); } void kasfUnpauseBuildShips(void) { cmUnPauseAllJobs(); } /*----------------------------------------------------------------------------- Name : kasfOtherKASPause/kasfOtherKASUnpause Description : Pause/unPause global KAS watches and timers not associated with this FSM. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfOtherKASPause(void) { char scopedName[TIMER_NAME_MAX_LENGTH*2+2]; kasUnpausedTeam = CurrentTeamP; dbgAssert(CurrentMissionScope != KAS_SCOPE_MISSION); //make sure we're operating at least at FSM level scope sprintf(scopedName, "%s.", CurrentMissionScopeName); timTimerPauseAllNotScoped(scopedName); //pause all the other timers } void kasfOtherKASUnpause(void) { kasUnpausedTeam = NULL; timTimerUnpauseAll(); //unpause all paused timers } /*----------------------------------------------------------------------------- Name : kasfIntelEventEnded Description : Returns TRUE only once if a fleet intel/command subtitled speech event ends or the player hits SPACE to short-cut the event. Inputs : Outputs : Return : 1 if the current fleet intel subtitle expired, 2 if the user hit space in the sensors manager. ----------------------------------------------------------------------------*/ sdword kasfIntelEventEnded(void) { sdword returnValue = subMessageEnded; subMessageEnded = 0; //only return TRUE once for each event // safety to make sure eventualy intel event ends if (!returnValue) { if (subMessageReturnedFalseTime == 0.0f) { subMessageReturnedFalseTime = universe.totaltimeelapsed; } else { if ( ((universe.totaltimeelapsed - subMessageReturnedFalseTime) > SUBMESSAGE_SAFETY_TIMEOUT) && (!subAnyCardsOnScreen()) ) { subMessageReturnedFalseTime = 0.0f; return 1; // subtitle finished by timeout } } } else { subMessageReturnedFalseTime = 0.0f; } return(returnValue); } /*----------------------------------------------------------------------------- Name : kasfIntelEventNotEnded Description : Clears the subMessageEnded flag. Should be called at the init of any FSM that will use "IntelEventEnded" Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfIntelEventNotEnded(void) { subMessageEnded = FALSE; } /*----------------------------------------------------------------------------- Name : kasfForceIntelEventEnded Description : Clears the subMessageEnded flag. Should be called at the init of any FSM that will use "IntelEventEnded" Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfForceIntelEventEnded(void) { subMessageEnded = TRUE; } /*----------------------------------------------------------------------------- Name : kasfSensorsStaticOn Description : Turns on sensors manager static Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfSensorsStaticOn(void) { static nisstatic newStatic; //needs to be persistant newStatic.index = NIS_SMStaticIndex; //!!! make these values tweakable (see nisStaticOnSet for an example) newStatic.nLines = 50; newStatic.nLinesVariation = 5; newStatic.width = primScreenToGLScaleX(10); newStatic.widthVariation = primScreenToGLScaleX(1); newStatic.y = primScreenToGLY(MAIN_WindowHeight / 2); newStatic.yVariation = primScreenToGLScaleY(MAIN_WindowHeight / 2); newStatic.hue = 0.5f; newStatic.hueVariation = 0.5f; newStatic.lum = 0.9f; newStatic.lumVariation = 0.1f; newStatic.sat = 0.5f; newStatic.satVariation = 0.1f; newStatic.alpha = 0.6f; newStatic.alphaVariation = 0.1f; newStatic.bAlpha = TRUE; newStatic.bTextured = FALSE; newStatic.texture = TR_InvalidInternalHandle; nisStaticOnExp(&newStatic); } /*----------------------------------------------------------------------------- Name : kasfSensorsStaticOff Description : Turns off static in the sensors manager. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfSensorsStaticOff(void) { nisStaticOffExp(NIS_SMStaticIndex); } /*----------------------------------------------------------------------------- Name : kasfGameEnd Description : Quit the game and play the exit plugscreens. Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void kasfGameEnd(void) { // this stuff only happens during demos #if defined(CGW) || defined (Downloadable) || defined(OEM) // quit the game here universe.quittime = universe.totaltimeelapsed; utyPlugScreens = TRUE; //spMainScreen(); //utyGameQuitToPlugScreens(NULL,NULL); #endif } /*----------------------------------------------------------------------------- Name : kasfSpawnEffect Description : Spawns an effect with a single float parameter Inputs : ships - ship(s) to spawn the effect on. effectName - name of the effect parameter - parameter to pass in (to be converted to a float) Outputs : Return : Note : the first parameter to the effect will be the size of the ship. ----------------------------------------------------------------------------*/ void kasfSpawnEffect(GrowSelection *ships, char *effectName, sdword parameter) { real32 floatParameter; udword intParameter, intSize, index, count; static char *lastName = NULL; static etgeffectstatic *lastEffect; Ship **shipPtr; //retain name so this lookup does not have ot happen every single time if (effectName != lastName) { lastName = effectName; lastEffect = etgEffectStaticFind(effectName, FALSE); #if ETG_ERROR_CHECKING if (lastEffect == NULL) { dbgFatalf(DBG_Loc, "Effect '%s' not found for KAS execution", effectName); } #endif } floatParameter = (real32)parameter; intParameter = TreatAsUdword(floatParameter); //get the user parameter count = ships->selection->numShips; shipPtr = ships->selection->ShipPtr; for (index = 0; index < count; index++, shipPtr++) { floatParameter = ((ShipStaticInfo *)((*shipPtr)->staticinfo))->staticheader.staticCollInfo.collspheresize; intSize = TreatAsUdword(floatParameter); //get the size etgEffectCreate(lastEffect, *shipPtr, NULL, NULL, NULL, 0.0f, EAF_Full, 2, intSize, intParameter); } }