/*============================================================================= Name : shipselect.c Purpose : Routines for manipulating SelectCommand structures Created 10/19/1997 by gshaw Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include "types.h" #include "spaceobj.h" #include "shipselect.h" #include "universe.h" #include "alliance.h" #include "attributes.h" #include "ProximitySensor.h" #include "SinglePlayer.h" #include "soundevent.h" #include "speechevent.h" #include "battle.h" /*----------------------------------------------------------------------------- Name : AddSpaceObjToSelectionBeforeIndex Description : Adds a SpaceObj to selection before index Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void AddSpaceObjToSelectionBeforeIndex(SpaceObj *obj,SpaceObjSelection *selection,sdword index) { sdword i; dbgAssert(index >= 0); dbgAssert(index < selection->numSpaceObjs); for (i=selection->numSpaceObjs;i>index;i--) { selection->SpaceObjPtr[i] = selection->SpaceObjPtr[i-1]; } selection->SpaceObjPtr[index] = obj; selection->numSpaceObjs++; } /*----------------------------------------------------------------------------- Name : AddSpaceObjToSelectionAfterIndex Description : Adds a SpaceObj to selection after index Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void AddSpaceObjToSelectionAfterIndex(SpaceObj *obj,SpaceObjSelection *selection,sdword index) { sdword i; dbgAssert(index >= 0); dbgAssert(index < selection->numSpaceObjs); index++; for (i=selection->numSpaceObjs;i>index;i--) { selection->SpaceObjPtr[i] = selection->SpaceObjPtr[i-1]; } selection->SpaceObjPtr[index] = obj; selection->numSpaceObjs++; } /*----------------------------------------------------------------------------- Name : RemoveSpaceObjFromSelectionPreserveOrder Description : removes a space obj from the selection, while preserving order Inputs : selection, obj Outputs : Return : ----------------------------------------------------------------------------*/ bool RemoveSpaceObjFromSelectionPreserveOrder(SpaceObjSelection *selection,SpaceObj *obj) { sdword i; sdword numSpaceObjs = selection->numSpaceObjs; for (i=0;iSpaceObjPtr[i]) { for ( ;iSpaceObjPtr[i] = selection->SpaceObjPtr[i+1]; } selection->numSpaceObjs--; return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : RemoveTargetFromSelection Description : A useful utility to remove targets from selection Does not delete entry - just removes reference to it Inputs : removeTargetPtr Outputs : Return : Returns TRUE if any target was removed ----------------------------------------------------------------------------*/ bool clRemoveTargetFromSelection(SelectAnyCommand *selection,TargetPtr removeTargetPtr) { sdword i; bool removedAny = FALSE; for (i=0;inumTargets; ) { if (removeTargetPtr == selection->TargetPtr[i]) { removedAny = TRUE; // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; // we must check same index again because we put last array entry here // warning: leave this as continue because sometimes removeTargetPtr may be set to NULL to remove all null's } i++; } return removedAny; } /*----------------------------------------------------------------------------- Name : ShipInSelection Description : returns TRUE if ship is in selection Inputs : selection, ship Outputs : Return : ----------------------------------------------------------------------------*/ bool ShipInSelection(SelectCommand *selection,Ship *ship) { sdword i; for (i=0;inumShips;i++) { if (selection->ShipPtr[i] == ship) { return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : ShiptypeInSelection Description : Returns TRUE if the selection contains a ship of shiptype "Type" Inputs : selection - the selection to check, type - the type to check for Outputs : Return : TRUE if a ship of the specified type is found ----------------------------------------------------------------------------*/ udword ShiptypeInSelection(SelectCommand *selection, ShipType type) { udword i, count; for (i=0,count=0;inumShips;i++) { if (selection->ShipPtr[i]->shiptype == type) { count++; } } return count; } /*----------------------------------------------------------------------------- Name : FindFirstInstanceOfShipType Description : Returns the first ship in the selection of the specified type Inputs : selection - the selection to check, type - the type to check for Outputs : Return : A pointer to the first instance of the specified type ----------------------------------------------------------------------------*/ ShipPtr FindFirstInstanceOfShipType(SelectCommand *selection, ShipType type) { udword i; for (i = 0; inumShips; i++) { if (selection->ShipPtr[i]->shiptype == type) { return selection->ShipPtr[i]; } } return NULL; } /*----------------------------------------------------------------------------- Name : MakeShipsNotIncludeTheseShips Description : Makes sure that ships in selection do not include theseships Inputs : selection, theseships Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsNotIncludeTheseShips(SelectCommand *selection,SelectCommand *theseships) { sdword numTheseShips = theseships->numShips; sdword i; for (i=0;iShipPtr[i]); } } /*----------------------------------------------------------------------------- Name : AnyOfTheseShipsAreInSelection Description : returns true if any ships in theseShips are in selection Inputs : theseShips,selection Outputs : Return : returns true if any ships in theseShips are in selection ----------------------------------------------------------------------------*/ bool AnyOfTheseShipsAreInSelection(SelectCommand *theseShips,SelectCommand *selection) { sdword i,j; ShipPtr thisShip; for (i=0;inumShips;i++) { thisShip = theseShips->ShipPtr[i]; for (j=0;jnumShips;j++) { if (thisShip == selection->ShipPtr[j]) { return TRUE; } } } return FALSE; } /*----------------------------------------------------------------------------- Name : TheseShipsAreInSelection Description : returns true if all of these ships are in selection Inputs : theseShips, selection Outputs : Return : returns true if all of these ships are in selection ----------------------------------------------------------------------------*/ bool TheseShipsAreInSelection(SelectCommand *theseShips,SelectCommand *selection) { sdword i; sdword numShips = theseShips->numShips; if (numShips == 0) { return FALSE; } for (i=0;iShipPtr[i])) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : SelectionsAreEquivalent Description : tells whether selection1 and selection2 are focusing on the same ships (ignores order of objects in lists). Inputs : selection1, selection2 Outputs : Return : true if selection1 and selection2 are focusing on the same ships ----------------------------------------------------------------------------*/ bool SelectionsAreEquivalent(SelectCommand *selection1,SelectCommand *selection2) { sdword i,j; sdword numShips = selection1->numShips; ShipPtr matchship; bool matched; if (numShips != selection2->numShips) { return FALSE; } for (i=0;iShipPtr[i]; for (j=0;jShipPtr[j] == matchship) { matched = TRUE; break; } } if (!matched) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : SelectionsAreTotallyEquivalent Description : tells whether selection1 and selection2 are the same selections (including order). Inputs : selection1, selection2 Outputs : Return : true if selection1 and selection2 are the same ----------------------------------------------------------------------------*/ bool SelectionsAreTotallyEquivalent(SelectCommand *selection1,SelectCommand *selection2) { sdword numShips = selection1->numShips; sdword i; if (numShips != selection2->numShips) { return FALSE; } for (i=0;iShipPtr[i] != selection2->ShipPtr[i]) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : isShipAttackCapable Description : returns TRUE if ship is attack capable Inputs : ship Outputs : Return : returns TRUE if ship is attack capable ----------------------------------------------------------------------------*/ bool isShipAttackCapable(Ship *ship) { if (ship->staticinfo->custshipheader.CustShipAttack == NULL) { return FALSE; } else { return TRUE; } } /*----------------------------------------------------------------------------- Name : AreAllShipsAttackCapable Description : returns TRUE if all ships are attack capable Inputs : selection Outputs : Return : returns TRUE if all ships are attack capable ----------------------------------------------------------------------------*/ bool AreAllShipsAttackCapable(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;i++) { shipstatic = selection->ShipPtr[i]->staticinfo; if (shipstatic->custshipheader.CustShipAttack == NULL) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : AreAnyShipsAttackCapable Description : returns TRUE if any ships are attack capable Inputs : selection Outputs : Return : returns TRUE if any ships are attack capable ----------------------------------------------------------------------------*/ bool AreAnyShipsAttackCapable(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;i++) { shipstatic = selection->ShipPtr[i]->staticinfo; if (shipstatic->custshipheader.CustShipAttack != NULL) { return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : isShipPassiveAttackCapable Description : returns TRUE if ship is attack capable Inputs : ship Outputs : Return : returns TRUE if ship is attack capable ----------------------------------------------------------------------------*/ bool isShipPassiveAttackCapable(Ship *ship) { if (ship->staticinfo->custshipheader.CustShipAttackPassive == NULL) { return FALSE; } else { return TRUE; } } /*----------------------------------------------------------------------------- Name : AreAllShipsPassiveAttackCapable Description : returns TRUE if all ships are attack capable Inputs : selection Outputs : Return : returns TRUE if all ships are attack capable ----------------------------------------------------------------------------*/ bool AreAllShipsPassiveAttackCapable(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;i++) { shipstatic = selection->ShipPtr[i]->staticinfo; if (shipstatic->custshipheader.CustShipAttackPassive == NULL) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : AreAnyShipsPassiveAttackCapable Description : returns TRUE if any ships are attack capable Inputs : selection Outputs : Return : returns TRUE if any ships are attack capable ----------------------------------------------------------------------------*/ bool AreAnyShipsPassiveAttackCapable(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;i++) { shipstatic = selection->ShipPtr[i]->staticinfo; if (shipstatic->custshipheader.CustShipAttackPassive != NULL) { return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : MakeShipsAttackCapable Description : Makes sure that the ships in this selection are capable of attack. Removes any ships from this selection that are not capable of attacking. Inputs : source - selection to cull Outputs : dest - culled selection Return : number of ships in culled selection Note : source and dest can safely be the same selection. ----------------------------------------------------------------------------*/ sdword MakeShipsAttackCapable(SelectCommand *dest, SelectCommand *source) { /* sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; if (shipstatic->custshipheader.CustShipAttack == NULL) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } */ sdword index, numShips = 0; for (index = 0; index < source->numShips; index++) { if (source->ShipPtr[index]->staticinfo->custshipheader.CustShipAttack != NULL) { dest->ShipPtr[numShips] = source->ShipPtr[index]; numShips++; } } dest->numShips = numShips; return(numShips); } /*----------------------------------------------------------------------------- Name : ShipCanHarvest Description : returns TRUE if ship can harvest Inputs : Outputs : Return : returns TRUE if ship can harvest ----------------------------------------------------------------------------*/ bool ShipCanHarvest(ShipStaticInfo *shipstatic) { if (shipstatic->shiptype == ResourceCollector) { return TRUE; } return FALSE; } /*----------------------------------------------------------------------------- Name : MakeShipsHarvestCapable Description : Makes a selection of just ships that are harvesters. Inputs : source - selection to search through Outputs : dest - where to store the culled selection Return : number of ships in culled selection ----------------------------------------------------------------------------*/ sdword MakeShipsHarvestCapable(SelectCommand *dest, SelectCommand *source) { /* sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; if (!ShipCanHarvest(shipstatic)) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } */ sdword index, numShips = 0; for (index = 0; index < source->numShips; index++) { if (ShipCanHarvest(source->ShipPtr[index]->staticinfo)) { dest->ShipPtr[numShips] = source->ShipPtr[index]; numShips++; } } dest->numShips = numShips; return(numShips); } /*----------------------------------------------------------------------------- Name : ShipCanGuard Description : returns TRUE if ship is capable of guarding Inputs : Outputs : Return : returns TRUE if ship is capable of guarding ----------------------------------------------------------------------------*/ bool ShipCanGuard(ShipStaticInfo *shipstatic) { if (shipstatic->shiptype == Mothership) { return FALSE; } if (shipstatic->shiptype == Probe) { return FALSE; } /* if (shipstatic->shiptype == ProximitySensor) { return FALSE; } */ #if 0 if (shipstatic->shiptype == ResearchShip) { return FALSE; } if (shipstatic->shiptype == SensorArray) { return FALSE; } #endif return TRUE; } /*----------------------------------------------------------------------------- Name : MakeShipsGuardCapable Description : Makes sure that the ships in this selection are capable of guarding. Removes any ships from this selection that are not capable of guarding. Inputs : selection Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsGuardCapable(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; if (!ShipCanGuard(shipstatic)) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : makeShipsDockCapable Description : removes ships that shouldn't be docking from the selection Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void makeShipsDockCapable(SelectCommand *selection) { sdword i; Ship *ship; if (playPackets) { return; } for (i=0;inumShips;) { //remove probe from selection..shouldn't dock! ship = selection->ShipPtr[i]; if ((ship->shiptype == Probe) || (ship->shiptype == TargetDrone) || (ship->shiptype == SensorArray)) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : makeShipsRetireable Description : removes ships that shouldn't be retiring from the selection Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void makeShipsRetireable(SelectCommand *selection) { sdword i; Ship *ship; for (i=0;inumShips;) { //remove probe from selection..shouldn't dock! ship = selection->ShipPtr[i]; if ((ship->shiptype == Probe) || (ship->shiptype == TargetDrone)) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : makeShipsNotIncludeSinglePlayerMotherships Description : If in single player, removes motherships from the selection Inputs : selection - selection to cull Outputs : Return : ----------------------------------------------------------------------------*/ void makeShipsNotIncludeSinglePlayerMotherships(SelectCommand *selection) { MakeShipsMobile(selection); } /*----------------------------------------------------------------------------- Name : makeShipsControllable Description : Removes ships from the selection such that all ships left in the selction aren't docking and can be freely ordered Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void makeShipsControllable(SelectCommand *selection,sdword newCommand) { sdword i; CommandToDo *command; if (playPackets) { // playing back game, user should be able to do NOTHING //selection->numShips = 0; return; } if(newCommand == COMMAND_HALT) { return; } for (i=0;inumShips;) { command = getShipAndItsCommand(&universe.mainCommandLayer,selection->ShipPtr[i]); if(command != NULL) { if(command->ordertype.order == COMMAND_DOCK || command->ordertype.order == COMMAND_LAUNCHSHIP) { //if docking ship is NULL, we can assume some stuff... if (selection->ShipPtr[i]->dockingship != NULL) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. /////////////////////// //Cannot Comply speech event! //Use Battle Chatter to filter //if SHOULDn't be called for move's that are cancelled.. //then we'll add a flag that gets passed it turning this on or off //event num: COMM_CannotComply //BCE_CannotComply /////////////////////// if (battleCanChatterAtThisTime(BCE_CannotComply, selection->ShipPtr[i]->dockingship)) { battleChatterAttempt(SOUND_EVENT_DEFAULT, BCE_CannotComply, selection->ShipPtr[i]->dockingship, SOUND_EVENT_DEFAULT); } if(selection->ShipPtr[i]->shiptype != ResearchShip) { selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } } } } i++; } } void makeSelectionHyperspaceCapable(SelectCommand *selection) { sdword i; //remove all NON-hyperspaceable ships! for(i=0;inumShips;) { if(!TW_HyperSpaceCostStruct[selection->ShipPtr[i]->shiptype].canMpHyperspace) { selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsSpecialActivateCapable Description : Makes sure that the ships in this selection are capable of the special activate. Removes any ships from this selection that are not Inputs : selection Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsSpecialActivateCapable(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; if (shipstatic->custshipheader.CustShipSpecialActivate == NULL) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsSpecialTargetCapable Description : Makes sure that the ships in this selection are capable of special targeting. Removes any ships from this selection that are not Inputs : selection - selection to neuter bFriendlies - if TRUE, only select ships that can z-bandbox friendlies, otherwise only ships that can z-bandbox enemies Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsSpecialTargetCapable(SelectCommand *selection, bool bFriendlies) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; // if (shipstatic->custshipheader.CustShipSpecialTarget == NULL) // { if (shipstatic->custshipheader.CustShipSpecialTarget != NULL) { if (bFriendlies) { //if we're targeting friendlies and ship can do so if (shipstatic->canSpecialBandBoxFriendlies) { i++; //leave this ship as is continue; } } else { //if we're targeting enemies and ship can do so if (!shipstatic->canSpecialBandBoxFriendlies) { i++; //leave this ship as is continue; } } } // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here // } // i++; } } bool AreShipsMobile(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;i++) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; if (shipstatic->staticheader.immobile) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : MakeShipsMobile Description : Makes sure that the ships in this selection are mobile Removes any ships from this selection that are not mobile. Inputs : selection Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsMobile(SelectCommand *selection) { sdword i; ShipStaticInfo *shipstatic; for (i=0;inumShips;) { shipstatic = (ShipStaticInfo *)selection->ShipPtr[i]->staticinfo; if (shipstatic->staticheader.immobile) { if ((shipstatic->shiptype == Mothership) && (selection->ShipPtr[i]->playerowner == universe.curPlayerPtr)) { speechEventFleet(COMM_F_MoShip_CantMove, 0, universe.curPlayerIndex); } // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : makeShipsFormationCapable Description : removes ships that can't go into formation Inputs : selection Outputs : Return : ----------------------------------------------------------------------------*/ void makeShipsFormationCapable(SelectCommand *selection) { sdword i; Ship *ship; for (i=0;inumShips;) { ship = selection->ShipPtr[i]; if (ship->shiptype == Probe) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsNonCapital Description : Makes sure that the ships in this selection are not capital ships. Removes any capital ships from this selection. Inputs : selection Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsNonCapital(SelectCommand *selection) { sdword i; for (i=0;inumShips;) { if (isCapitalShip(selection->ShipPtr[i])) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsOnlyCapital Description : Makes sure that the ships in this selection are only capital ships Inputs : selection - the selection to lookat Outputs : Removes non capital ships from the selection Return : void ----------------------------------------------------------------------------*/ void MakeShipsOnlyCapital(SelectCommand *selection) { sdword i; for (i=0;inumShips;) { if (isCapitalShip(selection->ShipPtr[i])) { i++; } else { selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; } } } /*----------------------------------------------------------------------------- Name : MakeShipsOnlyFollowConstraints Description : General routine that makes all ships in selection follow constraints set out by shipConstraintsCB callback function. Inputs : selection, shipConstraintsCB Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsOnlyFollowConstraints(SelectCommand *selection,ShipConstraintsCB shipConstraintsCB) { sdword i; for (i=0;inumShips;) { if (!shipConstraintsCB(selection->ShipPtr[i])) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : DoAllShipsFollowConstraints Description : Returns TRUE if all ships in selection follow shipConstraintsCB Inputs : selection, shipConstraintsCB Outputs : Return : Returns TRUE if all ships in selection follow shipConstraintsCB ----------------------------------------------------------------------------*/ bool DoAllShipsFollowConstraints(SelectCommand *selection,ShipConstraintsCB shipConstraintsCB) { sdword i; for (i=0;inumShips;i++) { if (!shipConstraintsCB(selection->ShipPtr[i])) { return FALSE; } } return TRUE; } /*----------------------------------------------------------------------------- Name : DoAnyShipsFollowConstraints Description : Returns TRUE if any ships in selection follow shipConstraintsCB Inputs : selection, shipConstraintsCB Outputs : Return : Returns TRUE if any ships in selection follow shipConstraintsCB ----------------------------------------------------------------------------*/ bool DoAnyShipsFollowConstraints(SelectCommand *selection,ShipConstraintsCB shipConstraintsCB) { sdword i; for (i=0;inumShips;i++) { if (shipConstraintsCB(selection->ShipPtr[i])) { return TRUE; } } return FALSE; } /*----------------------------------------------------------------------------- Name : MakeTargetsNotIncludeMissiles Description : Makes sure that the targets in selection are not missiles. Inputs : selection Outputs : Return : ----------------------------------------------------------------------------*/ void MakeTargetsNotIncludeMissiles(SelectAnyCommand *selection) { sdword i; for (i=0;inumTargets;) { if ((selection->TargetPtr[i])->objtype == OBJ_MissileType) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeTargetsOnlyEnemyShips Description : Makes sure that the targets in this selection are ships and are enemies (not curplayer's ships) Inputs : selection,curplayer Outputs : Return : ----------------------------------------------------------------------------*/ void MakeTargetsOnlyEnemyShips(SelectAnyCommand *selection,Player *curplayer) { sdword i; SpaceObjRotImpTarg *target; for (i=0;inumTargets;) { target = selection->TargetPtr[i]; if ((target->objtype != OBJ_ShipType) || (((Ship *)target)->shiptype == Drone) || // Drones not considered ships in this case (((Ship *)target)->playerowner == curplayer) || allianceIsShipAlly((Ship *)target, curplayer)) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeTargetsOnlyNonForceAttackTargets Description : Makes sure that the targets in this selection are ships and are enemies (not curplayer's ships) Inputs : selection,curplayer Outputs : Return : ----------------------------------------------------------------------------*/ void MakeTargetsOnlyNonForceAttackTargets(SelectAnyCommand *selection,Player *curplayer) { sdword i; SpaceObjRotImpTarg *target; for (i=0;inumTargets;) { target = selection->TargetPtr[i]; if ((target->objtype == OBJ_DerelictType) && (((Derelict *)target)->derelicttype == HyperspaceGate)) { goto dontremove; } if (target->attributes & (ATTRIBUTES_KillerCollDamage|ATTRIBUTES_HeadShotKillerCollDamage)) { goto dontremove; } if ((target->objtype != OBJ_ShipType) || (((Ship *)target)->shiptype == Drone) || // Drones not considered ships in this case (((Ship *)target)->shiptype == JunkYardHQ) || (((Ship *)target)->playerowner == curplayer) || allianceIsShipAlly((Ship *)target, curplayer)) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; // we must check same index again because we put last array entry here } dontremove: i++; } } /*----------------------------------------------------------------------------- Name : MakeTargetsSalvageable Description : Filters the targets for any ship or derelict that's salvageable Inputs : selection - the targets to filter, curplayer - determines while player is enemy Outputs : Changes selection Return : void ----------------------------------------------------------------------------*/ void MakeTargetsSalvageable(SelectAnyCommand *selection, Player *curplayer) { udword i; SpaceObjRotImpTarg *target; for (i=0;inumTargets;) { target = selection->TargetPtr[i]; if (target->objtype == OBJ_DerelictType) { /*switch (((Derelict *)target)->derelicttype) { case AngelMoon: case AngelMoon_clean: case Homeworld: case PlanetOfOrigin: case PlanetOfOrigin_scarred: case Scaffold: case Scaffold_scarred: case ScaffoldFingerA_scarred: case ScaffoldFingerB_scarred: //Don't salvage these selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; break; default: break; }*/ if (!((DerelictStaticInfo *)target->staticinfo)->salvageable) { selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; } } //!!!Single Player Game Mission Specific Code!!! //here's what's happening: //if it's a ship (but not a drone) //and it's not the players or an allies //exceptions to the rule are CryoTrays - they can always be salvaged //except for single player Mission 1 else if (target->objtype == OBJ_ShipType) { if ((((Ship *)target)->shiptype == Drone) || // Drones not considered ships in this case ( ( (((Ship *)target)->shiptype != CryoTray) || (singlePlayerGameInfo.currentMission == 1) ) && // Don't salvage player's or ally's shis, unless they are CryoTrays (( (((Ship *)target)->playerowner == curplayer) || allianceIsShipAlly((Ship *)target, curplayer) ) && !bitTest(((Ship *)target)->flags, SOF_Disabled)) )) { selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; } } else { selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; } i++; } } /*----------------------------------------------------------------------------- Name : MakeSelectionNotHaveCloakedEnemyShips Description : Removes enemy cloaked ships from the selection Inputs : selection - the selection being filtered, curplayer - the current player Outputs : Return : void ----------------------------------------------------------------------------*/ void MakeSelectionNotHaveCloakedEnemyShips(SelectCommand *selection, Player *curplayer) { sdword i; ShipPtr ship; for (i=0;inumShips;) { ship = selection->ShipPtr[i]; if ((ship->playerowner != curplayer) && (bitTest(ship->flags, SOF_Cloaked))) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue;// we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : makeShipsNotHaveNonCombatShipsForGuardAttack Description : Removes CloakGen...and other related ships so that selection can be given an ATATCK order while guarding and such that the cloak gen and other ships are left guarding Inputs : selection - the selection being filtered, Outputs : Return : void ----------------------------------------------------------------------------*/ void makeShipsNotHaveNonCombatShipsForGuardAttack(SelectCommand *selection) { sdword i; ShipPtr ship; for (i=0;inumShips;) { ship = selection->ShipPtr[i]; if (ship->shiptype == CloakGenerator || ship->shiptype == GravWellGenerator || ship->shiptype == DFGFrigate) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue;// we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeSelectionNotHaveNonVisibleEnemyShips Description : Removes non-visible enemy ships from the selection Note: takes into account Proximity Sensors detecting cloaked ships Inputs : selection - the selection being filtered, curplayer - the current player Outputs : Return : void ----------------------------------------------------------------------------*/ void MakeSelectionNotHaveNonVisibleEnemyShips(SelectCommand *selection, Player *curplayer) { sdword i; ShipPtr ship; for (i=0;inumShips;) { ship = selection->ShipPtr[i]; if ((ship->playerowner != curplayer) && (bitTest(ship->flags, SOF_Cloaked)) && (!proximityCanPlayerSeeShip(curplayer, ship))) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue;// we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeTargetsOnlyBeWithinRangeAndNotIncludeMe Description : Makes targets all be within range of comparewith, but don't include comparewith Inputs : selection, comparewith, range Outputs : Return : ----------------------------------------------------------------------------*/ void MakeTargetsOnlyBeWithinRangeAndNotIncludeMe(SelectAnyCommand *selection,SpaceObjRotImpTarg *comparewith,real32 range) { sdword i; SpaceObjRotImpTarg *target; real32 negrange = -range; vector diff; for (i=0;inumTargets;) { target = selection->TargetPtr[i]; vecSub(diff,target->posinfo.position,comparewith->posinfo.position); if ((target == comparewith) || !isBetweenExclusive(diff.x,negrange,range) || !isBetweenExclusive(diff.y,negrange,range) || !isBetweenExclusive(diff.z,negrange,range) ) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numTargets--; selection->TargetPtr[i] = selection->TargetPtr[selection->numTargets]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsFriendlyShips Description : Makes sure that the ships in this selection are enemies (not curplayer's ships) Removes any friendly ships from the selection Inputs : selection,curplayer Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsFriendlyShips(SelectCommand *selection,Player *curplayer) { ShipPtr ship; sdword i; for (i=0;inumShips;) { ship = selection->ShipPtr[i]; if ((ship->objtype != OBJ_ShipType) || (ship->playerowner != curplayer) ) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsFriendlyAndAlliesShips Description : Makes sure that the ships in this selection are curplayer's and allies ships Removes any enemy ships from the selection Inputs : selection,curplayer Outputs : Return : ----------------------------------------------------------------------------*/ void MakeShipsFriendlyAndAlliesShips(SelectCommand *selection,struct Player *curplayer) { sdword i; for (i=0;inumShips;) { if ((selection->ShipPtr[i]->objtype != OBJ_ShipType) || ( ((selection->ShipPtr[i])->playerowner != curplayer) && (!allianceIsShipAlly(selection->ShipPtr[i], curplayer)) ) ) { // to remove ShipPtr from list, decrement numShips and put last member // of array into slot being deleted. selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; // we must check same index again because we put last array entry here } i++; } } /*----------------------------------------------------------------------------- Name : makeshipMastersincludeslaves(SelectCommand *selection) Description : Checks the list of selected ships and if it finds a Master in the list, it adds the slaves aswell. Inputs : selection Outputs : none Return : none ----------------------------------------------------------------------------*/ void MakeShipMastersIncludeSlaves(SelectCommand *selection) { sdword i,count; Node *slavenode; count = selection->numShips; for (i=0;i < count;) { if ((selection->ShipPtr[i])->flags & SOF_Slaveable) { //ship is a most likely a master... if ((selection->ShipPtr[i])->slaveinfo->flags & SF_MASTER) { slavenode = (selection->ShipPtr[i])->slaveinfo->slaves.head; while(slavenode != NULL) { if(selection->numShips < COMMAND_MAX_SHIPS) { //haven't reached maximum so add slave onto end selection->ShipPtr[selection->numShips] = (Ship *)listGetStructOfNode(slavenode); selection->numShips++; } else { //reached max so break. break; } slavenode = slavenode->next; } } } i++; } } /*----------------------------------------------------------------------------- Name : selectAllCurrentPlayersNonHyperspacingShips Description : Selects all of the current player's non-hyperspacing ships Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ SelectCommand *selectAllCurrentPlayersNonHyperspacingShips(void) { SelectCommand *selection; sdword i = 0; Node *objnode; Ship *ship; selection = memAlloc(sizeofSelectCommand(universe.ShipList.num),"selectall",0); i = 0; objnode = universe.ShipList.head; while (objnode != NULL) { ship = (Ship *)listGetStructOfNode(objnode); dbgAssert(ship->objtype == OBJ_ShipType); if (allianceIsShipAlly(ship,universe.curPlayerPtr)) { if(!(ship->flags & SOF_Disabled)) { if ((!ShipCanHyperspace(ship)) && (ship->shiptype != Drone) && (ship->shiptype != CryoTray) && (ship->shiptype != Probe)) { selection->ShipPtr[i++] = ship; } } } objnode = objnode->next; } selection->numShips = i; return selection; } /*----------------------------------------------------------------------------- Name : selectAllCurrentPlayersHyperspacingShips Description : Selects all of the current player's hyperspacing ships Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ SelectCommand *selectAllCurrentPlayersHyperspacingShips(void) { SelectCommand *selection; sdword i = 0; Node *objnode; Ship *ship; selection = memAlloc(sizeofSelectCommand(universe.ShipList.num),"selectall",0); i = 0; objnode = universe.ShipList.head; while (objnode != NULL) { ship = (Ship *)listGetStructOfNode(objnode); dbgAssert(ship->objtype == OBJ_ShipType); if (allianceIsShipAlly(ship,universe.curPlayerPtr)) { if(!(ship->flags & SOF_Disabled)) { if (ShipCanHyperspace(ship)) { selection->ShipPtr[i++] = ship; } } } objnode = objnode->next; } selection->numShips = i; return selection; } /*----------------------------------------------------------------------------- Name : selectAllPlayersShips Description : selects all of a player's ships Inputs : player Outputs : Return : ----------------------------------------------------------------------------*/ SelectCommand *selectAllPlayersShips(struct Player *player) { SelectCommand *selection; sdword i = 0; Node *objnode; Ship *ship; selection = memAlloc(sizeofSelectCommand(universe.ShipList.num),"selectall",0); i = 0; objnode = universe.ShipList.head; while (objnode != NULL) { ship = (Ship *)listGetStructOfNode(objnode); dbgAssert(ship->objtype == OBJ_ShipType); if (ship->playerowner == player) { selection->ShipPtr[i++] = ship; } objnode = objnode->next; } selection->numShips = i; return selection; } /*----------------------------------------------------------------------------- Name : MakeSelectionNonResearchShips(SelectCommand *selectcom) Description : Removes all research ship types from the selection Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ void MakeSelectionNonResearchShips(SelectCommand *selectcom) { ubyte i; for (i = 0; i < selectcom->numShips;) { if(selectcom->ShipPtr[i]->shiptype == ResearchShip) { selectcom->numShips--; //decrease # of ships by 1 selectcom->ShipPtr[i] = selectcom->ShipPtr[selectcom->numShips]; //copy last ship ptr to recently removed shipptr index continue; } i++; } } /*----------------------------------------------------------------------------- Name : MakeShipsSingleClickSpecialCapable Description : Makes a selection of just ships that are have the canSingleClickSpecialActivate flag Inputs : source - selection to search through Outputs : dest - where to store the culled selection Return : number of ships in culled selection ----------------------------------------------------------------------------*/ sdword MakeShipsSingleClickSpecialCapable(SelectCommand *dest, SelectCommand *source) { /* sdword index; dest->numShips = 0; for (index = 0; index < source->numShips; index++) { if (source->ShipPtr[index]->staticinfo->canSingleClickSpecialActivate) { dest->ShipPtr[dest->numShips] = source->ShipPtr[index]; dest->numShips++; } } return(dest->numShips); */ sdword index, numShips = 0; for (index = 0; index < source->numShips; index++) { if (source->ShipPtr[index]->staticinfo->canSingleClickSpecialActivate) { dest->ShipPtr[numShips] = source->ShipPtr[index]; numShips++; } } dest->numShips = numShips; return(numShips); } /*----------------------------------------------------------------------------- Name : MakeShipsNotDocked Description : Makes a selection of ships that are not hiddel Inputs : Outputs : Return : ----------------------------------------------------------------------------*/ sdword MakeShipsNotHidden(SelectCommand *dest, SelectCommand *source) { sdword index, numShips = 0; for (index = 0; index < source->numShips; index++) { if (!bitTest(source->ShipPtr[index]->flags, SOF_Hide)) { dest->ShipPtr[numShips] = source->ShipPtr[index]; numShips++; } } dest->numShips = numShips; return(numShips); } /*----------------------------------------------------------------------------- Name : selectSelectionInterception Description : Returns a selection consisting of ships in both selection1 and selection2 Inputs : selection1, selection2 Outputs : Creates a new selection Return : the new selection, NULL if there's no intersection ----------------------------------------------------------------------------*/ SelectCommand *selectSelectionIntersection(SelectCommand *selection1, SelectCommand *selection2) { SelectCommand *smallerSelection, *largerSelection; SelectCommand *intersection = NULL; ShipPtr ship; sdword i; if (selection1->numShips < selection2->numShips) { smallerSelection = selection1; largerSelection = selection2; } else { smallerSelection = selection2; largerSelection = selection1; } intersection = selectDupSelection(smallerSelection); for (i=intersection->numShips-1; i >= 0; i--) { ship = intersection->ShipPtr[i]; if (!ShipInSelection(largerSelection, ship)) { clRemoveShipFromSelection(intersection, ship); } } if (!intersection->numShips) { memFree(intersection); intersection = NULL; } return intersection; } /*----------------------------------------------------------------------------- Name : selectMergeTwoSelections Description : Takes two selections and makes one big one. Note that a new selection is allocated in memory. Inputs : selection1, selection2 - the selections to merge Outputs : Allocates memory space for a new selection, frees the other two spaces Return : The new selection ----------------------------------------------------------------------------*/ SelectCommand *selectMergeTwoSelections(SelectCommand *selection1, SelectCommand *selection2, udword dealloc) { SelectCommand *new_selection; udword num_ships = 0, i, j; if (selection1 == NULL) { //if selection1 is NULL, copy selection2 into the new selection new_selection = (SelectCommand *)memAlloc(sizeofSelectCommand(selection2->numShips), "merge_sel2", 0); new_selection->numShips = selection2->numShips; for (i = 0; i < selection2->numShips; i++) { new_selection->ShipPtr[i] = selection2->ShipPtr[i]; } if ((dealloc == DEALLOC2) || (dealloc == DEALLOC_BOTH)) { memFree(selection2); } } else if (selection2 == NULL) { //if selection2 is NULL, copy selection1 into the new selection new_selection = (SelectCommand *)memAlloc(sizeofSelectCommand(selection1->numShips), "merge_sel1", 0); new_selection->numShips = selection1->numShips; for (i = 0; i < selection1->numShips; i++) { new_selection->ShipPtr[i] = selection1->ShipPtr[i]; } if ((dealloc == DEALLOC1) || (dealloc == DEALLOC_BOTH)) { memFree(selection1); } } else { MakeShipsNotIncludeTheseShips(selection1, selection2); new_selection = (SelectCommand *)memAlloc(sizeofSelectCommand(selection1->numShips + selection2->numShips), "merge_sel", 0); for (i = 0; i < selection1->numShips; i++) { new_selection->ShipPtr[i] = selection1->ShipPtr[i]; } for (j = 0; j < selection2->numShips; j++, i++) { new_selection->ShipPtr[i] = selection2->ShipPtr[j]; } new_selection->numShips = i; switch (dealloc) { case DEALLOC1: memFree(selection1); break; case DEALLOC2: memFree(selection2); break; case DEALLOC_BOTH: memFree(selection1); memFree(selection2); break; default: break; } } return new_selection; } /*----------------------------------------------------------------------------- Name : selectMemDupSelection Description : Creates a new selection that is an exact duplicate of another selection Inputs : selection - the selection to duplicate flag - the memory allocation flag Outputs : Allocates memory for the new selection Return : The new selection ----------------------------------------------------------------------------*/ SelectCommand *selectMemDupSelection(SelectCommand *selection, char *str, udword mmflag) { SelectCommand *new_selection; new_selection = (SelectCommand *)memAlloc(sizeofSelectCommand(selection->numShips), str, mmflag); memcpy(new_selection,selection,sizeofSelectCommand(selection->numShips)); return new_selection; } /*----------------------------------------------------------------------------- Name : MothershipOrCarrierIndexInSelection Description : returns index where a mothership or carrier is in selection. -1 if none found. Mothership has higher priority Inputs : Outputs : Return : returns index where a mothership or carrier is in selection. -1 if none found ----------------------------------------------------------------------------*/ sdword MothershipOrCarrierIndexInSelection(SelectCommand *selection) { sdword numShips = selection->numShips; sdword index = -1; sdword i; ShipType type; // go through selection to find index where a mothership or carrier is. Give higher priority to motherships. for (i=0;iShipPtr[i]->shiptype; if ((type == Mothership) || (type == P1Mothership) || (type == P2Mothership)) { return i; } else if (type == Carrier) { index = i; } } return index; } /*============================================================================= Grow select functions =============================================================================*/ void growSelectAddShip(GrowSelection *growSelect,Ship *ship) { SelectCommand *shipList; // reserve more space if required if (growSelect->selection->numShips >= growSelect->maxNumShips) { growSelect->maxNumShips += GROWSELECT_ADDBATCH; shipList = memAlloc(sizeofSelectCommand(growSelect->maxNumShips), "regrowships", 0); memcpy(shipList, growSelect->selection, sizeofSelectCommand(growSelect->selection->numShips)); memFree(growSelect->selection); growSelect->selection = shipList; } growSelect->selection->ShipPtr[growSelect->selection->numShips] = ship; growSelect->selection->numShips += 1; } bool growSelectRemoveShip(GrowSelection *growSelect,Ship *ship) { return clRemoveShipFromSelection(growSelect->selection,ship); } /*----------------------------------------------------------------------------- Name : growSelectRemoveShipBySettingNULL Description : Remove ship references from a grow selection Inputs : Outputs : Return : TRUE if a ship reference was removed ----------------------------------------------------------------------------*/ bool growSelectRemoveShipBySettingNULL(GrowSelection *growSelect,Ship *ship) { SelectCommand *selection = growSelect->selection; sdword numShips; sdword i; if (selection == NULL) { return FALSE; } numShips = selection->numShips; for (i=0;iShipPtr[i] == ship) { selection->ShipPtr[i] = NULL; return TRUE; } } return FALSE; } void growSelectRemoveShipIndex(GrowSelection *growSelect,sdword index) { SelectCommand *selection = growSelect->selection; dbgAssert(index < selection->numShips); selection->numShips--; selection->ShipPtr[index] = selection->ShipPtr[selection->numShips]; } void growSelectInit(GrowSelection *growSelect) { growSelect->maxNumShips = GROWSELECT_INITIALBATCH; growSelect->selection = memAlloc(sizeofSelectCommand(GROWSELECT_INITIALBATCH), "growships", 0); growSelect->selection->numShips = 0; } void growSelectClose(GrowSelection *growSelect) { if (growSelect->selection) { memFree(growSelect->selection); growSelect->selection = NULL; } growSelect->maxNumShips = 0; } void growSelectReset(GrowSelection *growSelect) { growSelect->selection->numShips = 0; } void growSelectAddShipNoDuplication(GrowSelection *growSelect, Ship *ship) { if (!ShipInSelection(growSelect->selection, ship)) { growSelectAddShip(growSelect, ship); } } bool MakeSelectionKamikazeCapable(SelectCommand *selection) { sdword numShips = 0,i; for (i = 0; i < selection->numShips; ) { if(selection->ShipPtr[i]->staticinfo->shipclass != CLASS_Fighter && selection->ShipPtr[i]->staticinfo->shipclass != CLASS_Corvette && selection->ShipPtr[i]->staticinfo->shiptype != ResourceCollector) { selection->numShips--; selection->ShipPtr[i] = selection->ShipPtr[selection->numShips]; continue; } i++; } if(selection->numShips <= 0) return FALSE; return TRUE; }