/*=================================================================== Procedure : TURRET Fire At Target.. Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_TURRET_FIREATTARGET( register ENEMY * Enemy ) { OBJECT * TObject; TObject = (OBJECT*) Enemy->TShip; if( (Enemy->Type != ENEMY_MissileTurret) ) { if( Enemy->Object.Animating && !(Enemy->Object.CurAnimSeq == TURRETSEQ_Fire) ) { return; } }else{ if( Enemy->Object.Animating && (Enemy->Object.CurAnimSeq == TURRETSEQ_Opening ) ) { }else{ if( !Enemy->Object.Animating ) { SetCurAnimSeq( TURRETSEQ_Open, &Enemy->Object ); } } } AI_THINK( Enemy , true , true ); // Is it time to validate target ? if ( Enemy->Timer == 0.0F ) { if( !( Enemy->AIFlags & AI_ANYPLAYERINRANGE ) || !AI_ClearLOS( &Enemy->Object.Pos ,Enemy->Object.Group , &TObject->Pos ) ) { Enemy->AIFlags &= ~AI_ICANSEEPLAYER; SetCurAnimSeq( TURRETSEQ_Closing, &Enemy->Object ); AI_SetSCAN( Enemy ); return; } Enemy->Timer = RESET_VALIDATE_TIME + (float) Random_Range( (u_int16_t) RESET_VALIDATE_TIME ); }else{ Enemy->Timer -= framelag; if( Enemy->Timer < 0.0F ) Enemy->Timer = 0.0F; } Enemy->AIFlags |= AI_ICANSEEPLAYER; AI_UPDATEGUNS( Enemy ); }
/*------------------------------------------------------------------- Procedure : AI for a turret while its SCANNING.. Output : ENEMY * Enemy Output : Nothing -------------------------------------------------------------------*/ void AI_TURRET_SCAN( register ENEMY * Enemy ) { OBJECT * TObject; Enemy->Timer -= framelag; if( Enemy->Object.Animating ) { return; } // Scan for target if ( Enemy->Timer <= 0.0F ) { AI_THINK( Enemy , TRUE , TRUE ); if( Enemy->AIFlags & AI_ANYPLAYERINRANGE ) { SET_TARGET_PLAYERS; AI_GetDistToNearestTarget( Enemy ); switch( Tinfo->TFlags ) { case _TARGET_PLAYERS: TObject = Tinfo->TObject; if( AI_InViewCone( &Enemy->Object.Pos ,&Enemy->Object.Mat , &TObject->Pos, Enemy->Viewcone ) ) { if( AI_ClearLOS( &Enemy->Object.Pos, Enemy->Object.Group , &TObject->Pos ) ) { Enemy->AIFlags |= AI_ICANSEEPLAYER; SetCurAnimSeq( TURRETSEQ_Opening, &Enemy->Object ); Enemy->TShip = TObject; AI_SetFIREATTARGET( Enemy ); } } break; default: // Switch to AIMODE_IDLE Enemy->Object.AI_Mode = AIMODE_IDLE; Enemy->Timer = RESET_IDLE_TIME; break; } }else{ Enemy->Object.AI_Mode = AIMODE_IDLE; Enemy->Timer = RESET_IDLE_TIME; } } }
/*------------------------------------------------------------------- Procedure : Exogenon Idle Input : ENEMY * Enemy Output : Nothing -------------------------------------------------------------------*/ void AI_EXOGENON_IDLE( register ENEMY * Enemy ) { int i; int startpos = 0; float Distance = 0.0F; AI_THINK( Enemy , TRUE , TRUE ); if( Enemy->Object.CurAnimSeq != EXOGENONSEQ_Stop_Up ) { SetCurAnimSeq( EXOGENONSEQ_Stop_Up, &Enemy->Object ); return; } Enemy->Object.Pos = Exogenon_StartPos[0]; Enemy->Object.Pos.y += 256.0F * 10.0F; if( !(Enemy->AIFlags & AI_ANYPLAYERINRANGE) ) return; if( Enemy->Timer ) { Enemy->Timer -= framelag; if( Enemy->Timer <= 0.0F ) { Enemy->Timer = 0.0F; } return; } startpos = Random_Range( (uint16) Exogenon_Num_StartPos); i = Exogenon_Num_StartPos; while( Distance < (SHIP_RADIUS * 3.0F ) && i >= 0 ) { Enemy->Object.Pos = Exogenon_StartPos[startpos]; startpos++; if( startpos >= Exogenon_Num_StartPos ) startpos = 0; Distance = DistanceVector2Vector( &Enemy->Object.Pos,&Ships[WhoIAm].Object.Pos ); i--; } SetCurAnimSeq( EXOGENONSEQ_Move_Down, &Enemy->Object ); Enemy->Object.AI_Mode = AIMODE_EXOGENON_MOVEDOWN; }
/*=================================================================== Procedure : AIR Formation Flying Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_LITTLEGEEK_FORMATION( register ENEMY * Enemy ) { OBJECT * SObject; VECTOR Offset; VECTOR TargetPos; ENEMY * LinkEnemy; SObject = &Enemy->Object; // Is it time to think??? AI_THINK( Enemy , false ,false); LinkEnemy = Enemy->FormationLink; if( !LinkEnemy || ( LinkEnemy->Object.Shield <= (EnemyTypes[LinkEnemy->Type].Shield * 0.5F ) ) ) { Enemy->Object.ControlType = ENEMY_CONTROLTYPE_FLY_AI; EnemyTypes[ENEMY_Boss_LittleGeek].Radius = 800 * GLOBAL_SCALE; EnemyTypes[ENEMY_Boss_BigGeek].Radius = 900.0F * GLOBAL_SCALE; AI_SetDOGFIGHT( Enemy ); SetCurAnimSeq( LITTLEGEEKSEQ_Open, &Enemy->Object ); Enemy->FormationLink = NULL; return; } SetCurAnimSeq( LITTLEGEEKSEQ_Stop, &Enemy->Object ); Offset = Enemy->FormationOffset; ApplyMatrix( &LinkEnemy->Object.Mat, &Offset, &TargetPos ); TargetPos.x += LinkEnemy->Object.Pos.x; TargetPos.y += LinkEnemy->Object.Pos.y; TargetPos.z += LinkEnemy->Object.Pos.z; Enemy->Object.Pos = TargetPos; Enemy->Object.Quat = LinkEnemy->Object.Quat; Enemy->Object.Mat = LinkEnemy->Object.Mat; Enemy->Object.InvMat = LinkEnemy->Object.InvMat; Enemy->Object.FinalMat = LinkEnemy->Object.FinalMat; Enemy->Object.FinalInvMat = LinkEnemy->Object.FinalInvMat; EnemyTypes[ENEMY_Boss_LittleGeek].Radius = 0.0F; }
/*=================================================================== Procedure : AIR Formation Flying Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_AIR_FORMATION( register ENEMY * Enemy ) { float Dist; OBJECT * TObject; OBJECT * SObject; VECTOR NewPos; VECTOR TempVector; VECTOR TempUpVector; VECTOR TempOffset = { 0.0F, 0.0F, 0.0F }; VECTOR Offset; VECTOR TargetPos; VECTOR TempDir; ENEMY * LinkEnemy; SObject = &Enemy->Object; // Is it time to think??? AI_THINK( Enemy , false ,false); LinkEnemy = Enemy->FormationLink; if( !LinkEnemy || ( LinkEnemy->Object.AI_Mode == AIMODE_RETREAT ) ) { if( Enemy->AIFlags & ( AI_ICANSEEPLAYER + AI_ICANHEARPLAYER ) ) { AI_SetDOGFIGHT( Enemy ); return; }else{ AI_SetFOLLOWPATH( Enemy ); return; } } TObject = (OBJECT*) Enemy->TShip; Enemy->Timer -= framelag; if( Enemy->Timer < 0.0F ) Enemy->Timer = 0.0F; Enemy->PrimaryFireTimer -= framelag; if( Enemy->PrimaryFireTimer < 0.0F ) Enemy->PrimaryFireTimer = 0.0F; Enemy->SecondaryFireTimer -= framelag; if( Enemy->SecondaryFireTimer < 0.0F ) Enemy->SecondaryFireTimer = 0.0F; if( Enemy->AIFlags & ( AI_ICANSEEPLAYER + AI_ICANHEARPLAYER ) ) { Enemy->TNode = NULL; if( !(Enemy->Object.Flags & SHIP_Scattered ) && (Enemy->AIFlags & AI_ICANSEEPLAYER) && !(Enemy->AIFlags & AI_FRIENDLYFIRE) ) { ApplyMatrix( &SObject->Mat, &Forward, &TempVector ); ApplyMatrix( &SObject->Mat, &SlideUp, &TempUpVector ); if( (Enemy->PrimaryFireTimer == 0.0F) && ( EnemyTypes[Enemy->Type].PrimaryWeaponType != NO_PRIMARY ) ) { Enemy->PrimaryFireTimer = EnemyTypes[Enemy->Type].PrimaryFireRate + (float) Random_Range( (u_int16_t) EnemyTypes[Enemy->Type].PrimaryFireRate ); EnemyFirePrimary( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, EnemyTypes[Enemy->Type].PrimaryWeaponType, Enemy->Object.Group, &Enemy->Object.Pos, &TempOffset, &TempVector, &TempUpVector, EnemyTypes[Enemy->Type].PowerLevel, 0.0F, false, NULL ); } } } if( (Enemy->Object.Flags & SHIP_Scattered ) || ( (EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_RETREAT) && ( Enemy->Object.Shield <= (EnemyTypes[Enemy->Type].Shield * 0.15 ) ) ) ) { // we should get out of hear.. Enemy->FormationLink = NULL; AI_SetRETREAT( Enemy ); return; } AI_UPDATEGUNS( Enemy ); // Aim at target if( TObject && ( Enemy->AIFlags & AI_ICANSEEPLAYER ) ) { if( EnemyTypes[Enemy->Type].PrimaryWeaponType != NO_PRIMARY ) { AI_LookAhead( EnemyTypes[Enemy->Type].Behave.Anticipate_Move , &Enemy->Object.Pos , TObject , &NewPos , PrimaryWeaponAttribs[EnemyTypes[Enemy->Type].PrimaryWeaponType].Speed[0] ); }else{ NewPos = TObject->Pos; } AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &NewPos ); if( !( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ICANTPITCH ) ) { Enemy->AIMoveFlags |= AimData.Flags; }else{ //This enemy cant look up or down so it has to move up and down to compensate.... Enemy->AIMoveFlags |= ( AimData.Flags & ( AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ) ); if( AimData.Flags & AI_CONTROL_TURNUP ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; }else if( AimData.Flags & AI_CONTROL_TURNDOWN ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } } Enemy->AI_Angle = AimData.Angle; }else{ ApplyMatrix( &LinkEnemy->Object.Mat, &Forward, &TempDir ); TempDir.x *= 1024.0F * GLOBAL_SCALE * 5.0F; TempDir.y *= 1024.0F * GLOBAL_SCALE * 5.0F; TempDir.z *= 1024.0F * GLOBAL_SCALE * 5.0F; NewPos.x = LinkEnemy->Object.Pos.x + TempDir.x; NewPos.y = LinkEnemy->Object.Pos.y + TempDir.y; NewPos.z = LinkEnemy->Object.Pos.z + TempDir.z; AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &NewPos ); if( !( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ICANTPITCH ) ) { Enemy->AIMoveFlags |= AimData.Flags; }else{ //This enemy cant look up or down so it has to move up and down to compensate.... Enemy->AIMoveFlags |= ( AimData.Flags & ( AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ) ); if( AimData.Flags & AI_CONTROL_TURNUP ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; }else if( AimData.Flags & AI_CONTROL_TURNDOWN ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } } Enemy->AI_Angle = AimData.Angle; } if( Enemy->AvoidTimer ) { Enemy->AIMoveFlags = Enemy->AvoidType; }else{ Offset = Enemy->FormationOffset; ApplyMatrix( &LinkEnemy->Object.Mat, &Offset, &TargetPos ); TargetPos.x += LinkEnemy->Object.Pos.x; TargetPos.y += LinkEnemy->Object.Pos.y; TargetPos.z += LinkEnemy->Object.Pos.z; Dist = DistanceVector2Vector( &TargetPos , &Enemy->Object.Pos); if( Dist > (EnemyTypes[Enemy->Type].Radius * 0.75F) ) { Offset.x = TargetPos.x - Enemy->Object.Pos.x; Offset.y = TargetPos.y - Enemy->Object.Pos.y; Offset.z = TargetPos.z - Enemy->Object.Pos.z; ApplyMatrix( &Enemy->Object.InvMat, &Offset, &TargetPos ); if( TargetPos.x < -(EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_LEFT; } if( TargetPos.x > (EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_RIGHT; } if( TargetPos.y < -(EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } if( TargetPos.y > (EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; } if( TargetPos.z < -(EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_BACK; } if( TargetPos.z > (EnemyTypes[Enemy->Type].Radius * 0.25F) ) { Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; } } } }
/*=================================================================== Procedure : AI Spline Movement.... Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_SPLINE_FOLLOWPATH( register ENEMY * Enemy ) { NODE * TNode; NODE * Node1; NODE * Node2; NODE * Node3; NODE * Node4; VECTOR OldPos; VECTOR MoveOffset; float Distance; float WantedDistance; float Time; float Tstep; VECTOR TempPos; int Count; OldPos = Enemy->Object.Pos; if( !Enemy->SplineNode1 ) { //We have to start TNode = Enemy->Object.NearestNode; Enemy->SplineNode1 = (void*) TNode; Enemy->SplineNode2 = (void*) TNode; Node1 = (NODE*)Enemy->SplineNode1; Node2 = (NODE*)Enemy->SplineNode2; Enemy->SplineNode3 = (void*) FindSuitableSplineNode( Enemy->Object.NodeNetwork ,Node2 , Node1 , Node2 , NULL , NULL ); Node3 = (NODE*)Enemy->SplineNode3; Enemy->SplineNode4 = (void*) FindSuitableSplineNode( Enemy->Object.NodeNetwork ,Node3 , Node1 , Node2 , Node3 , NULL ); } Node1 = (NODE*)Enemy->SplineNode1; Node2 = (NODE*)Enemy->SplineNode2; Node3 = (NODE*)Enemy->SplineNode3; Node4 = (NODE*)Enemy->SplineNode4; WantedDistance = (EnemyTypes[Enemy->Type].MaxMoveRate*0.65F) * framelag; Tstep = ( WantedDistance / DistanceVector2Vector( &Node2->Pos , &Node3->Pos ) ) * 0.1F; Distance = DistanceVector2Vector( &Node2->Pos , &Node3->Pos ); Time = (Distance / (EnemyTypes[Enemy->Type].MaxMoveRate * 0.65F) ); Distance = 0.0F; Count = 0; do { Enemy->Timer += Tstep; if( Enemy->Timer >= 1.0F ) { Enemy->SplineNode1 = Enemy->SplineNode2; Enemy->SplineNode2 = Enemy->SplineNode3; Enemy->SplineNode3 = Enemy->SplineNode4; Node1 = (NODE*)Enemy->SplineNode1; Node2 = (NODE*)Enemy->SplineNode2; Node3 = (NODE*)Enemy->SplineNode3; Enemy->Timer = ((Enemy->Timer - 1.0F) * Time); Distance = DistanceVector2Vector( &Node2->Pos , &Node3->Pos ); Time = (Distance / (EnemyTypes[Enemy->Type].MaxMoveRate*0.65F) ); Enemy->Timer /= Time; Enemy->SplineNode4 = (void*) FindSuitableSplineNodeRandom( Enemy->Object.NodeNetwork ,Node3 , Node1 , Node2 , Node3 , NULL ); Node4 = (NODE*)Enemy->SplineNode4; Tstep = ( WantedDistance / DistanceVector2Vector( &Node2->Pos , &Node3->Pos ) ) * 0.1F; if( Node3 && (Node3->Flags&NODE_TERMINATE) ) { KillUsedEnemy( Enemy ); return; } } TempPos = Enemy->Object.Pos; spline(&Enemy->Object.Pos, Enemy->Timer, &Node1->Pos, &Node2->Pos, &Node3->Pos, &Node4->Pos); Distance += DistanceVector2Vector( &Enemy->Object.Pos , &TempPos); Count++; }while( ( Distance < WantedDistance ) && (Count < 100) ); AI_THINK( Enemy , true , true); if( (Enemy->AIFlags & AI_ANYPLAYERINRANGE) ) { Enemy->PrimaryFireTimer -= framelag; if( Enemy->PrimaryFireTimer < 0.0F ) Enemy->PrimaryFireTimer = 0.0F; if(Enemy->PrimaryFireTimer == 0.0F) { if( !Enemy->TShip ) { AI_DO_SCAN( Enemy ); } Enemy->PrimaryFireTimer = RESET_VALIDATE_TIME + (float) Random_Range( (u_int16_t) RESET_VALIDATE_TIME ); } } AI_UPDATEGUNS( Enemy ); MoveOffset.x = Enemy->Object.Pos.x - OldPos.x; MoveOffset.y = Enemy->Object.Pos.y - OldPos.y; MoveOffset.z = Enemy->Object.Pos.z - OldPos.z; Enemy->Object.Group = MoveGroup( &Mloadheader, &OldPos, Enemy->Object.Group, &MoveOffset ); }
/*=================================================================== Procedure : AIR Retreat And run away Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_AIR_RETREAT( register ENEMY * Enemy ) { OBJECT * TObject; OBJECT * SObject; NODE * TNode; NODE * NewNode; SObject = &Enemy->Object; // Is it time to think??? AI_THINK( Enemy , false , false); TObject = (OBJECT*) Enemy->TShip; if( !TObject ) { AI_SetFOLLOWPATH( Enemy ); return; } Enemy->Timer -= framelag; if( Enemy->Timer < 0.0F ) Enemy->Timer = 0.0F; if( !Enemy->TNode ) { Enemy->TNode = Enemy->Object.NearestNode; Enemy->Timer = EnemyTypes[Enemy->Type].Behave.RetreatTime; // How long I Run away for... } AI_UPDATEGUNS( Enemy ); // Aim at target if( Enemy->TNode ) { if ( Enemy->Timer == 0.0F ) { // I Only have a certian amount of time to Run Away.. AI_SetFOLLOWPATH( Enemy ); return; } TNode = (NODE*) Enemy->TNode; AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &TNode->Pos ); if( !( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ICANTPITCH ) ) { Enemy->AIMoveFlags |= AimData.Flags; if( ( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_DONTSTOPANDTURN ) || ( (AimData.Angle.x < 15.0F) && (AimData.Angle.x > -15.0F) && (AimData.Angle.y < 15.0F) && (AimData.Angle.y > -15.0F) ) ) Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; }else{ //This enemy cant look up or down so it has to move up and down to compensate.... if( ( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_DONTSTOPANDTURN ) || ( (AimData.Angle.x < 15.0F) && (AimData.Angle.x > -15.0F) && (AimData.Angle.y < 15.0F) && (AimData.Angle.y > -15.0F) && (AimData.Angle.y < 3.0F) && (AimData.Angle.y > -3.0F)) ) Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; Enemy->AIMoveFlags |= ( AimData.Flags & ( AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ) ); if( AimData.Flags & AI_CONTROL_TURNUP ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; }else if( AimData.Flags & AI_CONTROL_TURNDOWN ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } } if( DistanceVector2Vector( &Enemy->Object.Pos , &TNode->Pos ) < 64.0F ) { Enemy->Object.NearestNode = TNode; if( !(Enemy->Object.NodeNetwork&TNode->NetMask) && Enemy->Object.LastNearestNode && !(EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_LEAVENETWORK) ) { // The node Im Targetting is not on my network...Better try and find one... TNode = WhichNode( 1 , Enemy->Object.NearestNode , Enemy->Object.LastNearestNode ); if( !TNode ) { Enemy->Object.LastNearestNode = NULL; return; } if( !AI_ClearLOSNonZero( &Enemy->Object, &TNode->Pos , EnemyTypes[Enemy->Type].Radius ) ) { // cant see the ideal node so just keep going to my previous target... }else{ Enemy->TNode = TNode; } }else{ // If I can leave my network to follow a target then do so if I have to... if( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_LEAVENETWORK ) NewNode = (void*) WhichRetreatNode( 1 , Enemy->Object.NearestNode , TObject->NearestNode ); else NewNode = (void*) WhichRetreatNode( Enemy->Object.NodeNetwork , Enemy->Object.NearestNode , TObject->NearestNode ); if( !NewNode || !AI_ClearLOSNonZero( &Enemy->Object, &NewNode->Pos , EnemyTypes[Enemy->Type].Radius ) ) { // cant see the ideal node so just keep going to my previous target... }else{ Enemy->TNode = NewNode; } } } }else{ Enemy->TNode = Enemy->Object.NearestNode; } Enemy->AI_Angle = AimData.Angle; }
/*=================================================================== Procedure : AIR Follow Path Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_AIR_FOLLOWPATH( register ENEMY * Enemy ) { OBJECT * SObject; NODE * TNode; VECTOR TempVector = { 0.0F , 0.0F , 0.0F }; VECTOR TempUpVector; VECTOR TempForwardVector; u_int16_t MineIndex; SObject = &Enemy->Object; AI_THINK( Enemy , false , false ); if( !(Enemy->AIFlags & AI_ANYPLAYERINRANGE) ) return; if( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ATTACK_ONSITE ) { Tinfo->Flags = 0; SET_TARGET_PLAYERS; AI_GetDistToNearestTarget( Enemy ); Enemy->TShip = Tinfo->TObject; } if( Enemy->TShip && ( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ATTACK_ONSITE ) ) { if( Enemy->AIFlags&AI_ICANSEEPLAYER ) { AI_SetDOGFIGHT( Enemy ); return; }else if( Enemy->AIFlags&AI_ICANHEARPLAYER ) { AI_SetMOVETOTARGET( Enemy ); return; } } if( (Enemy->AIFlags&AI_MINEAVOID) && (EnemyTypes[Enemy->Type].Behave.Flags&AI_BEHAVIOUR_ATTACKMINES) ) { Enemy->AvoidTimer = 0.0F; Enemy->AvoidType = 0; AI_SetKILLMINE( Enemy ); return; } if( TNode = (NODE*) Enemy->TNode ) { if( !(Enemy->Object.NodeNetwork&TNode->NetMask) ) { // The node Im Targetting is not on my network...Better try and find one... if( Enemy->Object.LastNearestNode ) { TNode = (NODE*) ( Enemy->TNode = WhichNode( 1 , Enemy->Object.NearestNode , Enemy->Object.LastNearestNode ) ); if( !TNode ) { AI_SetSCAN( Enemy ); return; } if( !AI_ClearLOSNonZero( &Enemy->Object, &TNode->Pos , EnemyTypes[Enemy->Type].Radius ) ) { // couldnt find a node that will take me to my target so go back to my nearest... TNode = (NODE*) ( Enemy->TNode = Enemy->Object.NearestNode ); } } } AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &TNode->Pos ); Enemy->AI_Angle = AimData.Angle; if( !( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_ICANTPITCH ) ) { Enemy->AIMoveFlags |= AimData.Flags; if( ( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_DONTSTOPANDTURN ) || ( (AimData.Angle.x < 15.0F) && (AimData.Angle.x > -15.0F) && (AimData.Angle.y < 15.0F) && (AimData.Angle.y > -15.0F) ) ) Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; }else{ //This enemy cant look up or down so it has to move up and down to compensate.... if( ( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_DONTSTOPANDTURN ) || ( (AimData.Angle.x < 15.0F) && (AimData.Angle.x > -15.0F) && (AimData.Angle.y < 15.0F) && (AimData.Angle.y > -15.0F) && (AimData.Angle.y < 3.0F) && (AimData.Angle.y > -3.0F)) ) Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; Enemy->AIMoveFlags |= ( AimData.Flags & ( AI_CONTROL_TURNLEFT + AI_CONTROL_TURNRIGHT ) ); if( AimData.Flags & AI_CONTROL_TURNUP ) { Enemy->AIMoveFlags |= AI_CONTROL_UP; }else if( AimData.Flags & AI_CONTROL_TURNDOWN ) { Enemy->AIMoveFlags |= AI_CONTROL_DOWN; } } if( DistanceVector2Vector( &Enemy->Object.Pos , &TNode->Pos ) < 64.0F ) { Tinfo->Flags = 0; SET_TARGET_NODES; AI_GetDistToNearestTarget( Enemy ); Enemy->TNode = Tinfo->TObject; } // MINES........ if( (Enemy->AIFlags&AI_MINEAVOID) && (EnemyTypes[Enemy->Type].Behave.Flags&AI_BEHAVIOUR_AVOIDMINES) ) { // A Mine is close....And I can See it... TNode = ChooseAlternateNode( Enemy->Object.NodeNetwork , Enemy->Object.NearestNode , Enemy->TNode ); Enemy->TNode = TNode; Enemy->AIFlags &= ~AI_MINEAVOID; Enemy->AIMoveFlags &= ~AI_CONTROL_FORWARD; } if( !Enemy->AvoidTimer) { TNode = Enemy->Object.NearestNode; if( (TNode->Flags&NODE_DROPMINES) && (EnemyTypes[Enemy->Type].Behave.Flags&AI_BEHAVIOUR_DROPMINES) ) { Enemy->SecondaryFireTimer -= framelag; if( Enemy->SecondaryFireTimer < 0.0F ) Enemy->SecondaryFireTimer = 0.0F; if( (Enemy->SecondaryFireTimer == 0.0F) ) { Enemy->SecondaryFireTimer = EnemyTypes[Enemy->Type].SecondaryFireRate + (float) Random_Range( (u_int16_t) EnemyTypes[Enemy->Type].SecondaryFireRate ); //This is where we Lay Mines.... ApplyMatrix( &Enemy->Object.Mat, &Forward, &TempForwardVector ); ApplyMatrix( &Enemy->Object.Mat, &SlideUp, &TempUpVector ); MineIndex = InitOneSecBull( OWNER_ENEMY, Enemy->Index, ++Enemy->BulletID, Enemy->Object.Group, &Enemy->Object.Pos, &TempVector, &TempForwardVector, &TempUpVector, &TempVector, EnemyTypes[Enemy->Type].SecondaryWeaponType, false ); if( MineIndex != (u_int16_t) -1 ) { SecBulls[MineIndex].LifeSpan = 10.0F * 60.0F; } } } } }else{ // If no target node has been found yet go to the nearest one... Enemy->TNode = Enemy->Object.NearestNode; } }
/*=================================================================== Procedure : CRAWL Follow Path Input : ENEMY * Enemy Output : Nothing ===================================================================*/ void AI_CRAWL_FOLLOWPATH( register ENEMY * Enemy ) { OBJECT * SObject; NODE * TNode; SObject = &Enemy->Object; AI_THINK( Enemy , false , false); if( !(Enemy->AIFlags & AI_ANYPLAYERINRANGE) ) return; Enemy->Timer -= framelag; if( Enemy->Timer < 0.0F ) Enemy->Timer = 0.0F; if(Enemy->Timer == 0.0F) { if( !(Enemy->AIFlags & AI_ICANSEEPLAYER )) { if( !Enemy->TShip ) { AI_DO_SCAN( Enemy ); } } Enemy->Timer = RESET_VALIDATE_TIME + (float) Random_Range( (u_int16_t) RESET_VALIDATE_TIME ); } AI_UPDATEGUNS( Enemy ); if( (Enemy->Type == ENEMY_Legz) || (Enemy->Type == ENEMY_LEADER_Legz) ) { if( !Enemy->Object.Animating ) { SetCurAnimSeq( 0, &Enemy->Object ); } Enemy->Object.AnimSpeed = 0.5F + ( ( Enemy->Object.Speed.z / EnemyTypes[Enemy->Type].MaxMoveRate ) * 2.0F ); } if( TNode = (NODE*) Enemy->TNode ) { if( !(EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_NOTURN) ) { AI_AimAtTarget( &Enemy->Object.InvMat , &Enemy->Object.Pos, &TNode->SolidPos ); Enemy->AIMoveFlags |= AimData.Flags; Enemy->AI_Angle = AimData.Angle; if( ( EnemyTypes[Enemy->Type].Behave.Flags & AI_BEHAVIOUR_DONTSTOPANDTURN ) || ( (AimData.Angle.y < 10.0F) && (AimData.Angle.y > -10.0F) ) ) { Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; } }else{ Enemy->AIMoveFlags |= AI_CONTROL_FORWARD; } if(Enemy->PickNewNodeNow) { Enemy->PickNewNodeNow = false; Enemy->LastTNode = TNode; if( !Enemy->NextTNode ) { Enemy->Object.NearestNode = TNode; Enemy->NextTNode = FindSuitableSplineNode( Enemy->Object.NodeNetwork, Enemy->Object.NearestNode , Enemy->Object.NearestNode , Enemy->LastTNode , Enemy->NextTNode , Enemy->TNode ); } TNode = Enemy->NextTNode; Enemy->TNode = TNode; if( TNode ) { Enemy->Object.NearestNode = TNode; Enemy->NextTNode = FindSuitableSplineNode( Enemy->Object.NodeNetwork, Enemy->Object.NearestNode , Enemy->Object.NearestNode , Enemy->LastTNode , Enemy->NextTNode , Enemy->TNode ); } return; } }else{ // If no target node has been found yet go to the nearest one... Enemy->TNode = Enemy->Object.NearestNode; Enemy->NextTNode = NULL; } }