00001
00002
00003
00004 #include "b_local.h"
00005 #include "g_nav.h"
00006 #include "anims.h"
00007
00008 void G_Cylinder( vec3_t start, vec3_t end, float radius, vec3_t color );
00009
00010 qboolean G_BoundsOverlap(const vec3_t mins1, const vec3_t maxs1, const vec3_t mins2, const vec3_t maxs2);
00011 int NAV_Steer( gentity_t *self, vec3_t dir, float distance );
00012 extern int GetTime ( int lastTime );
00013
00014 navInfo_t frameNavInfo;
00015 extern qboolean FlyingCreature( gentity_t *ent );
00016
00017 #include "../namespace_begin.h"
00018 extern qboolean PM_InKnockDown( playerState_t *ps );
00019 #include "../namespace_end.h"
00020
00021
00022
00023
00024
00025
00026
00027 qboolean NPC_ClearPathToGoal( vec3_t dir, gentity_t *goal )
00028 {
00029 trace_t trace;
00030 float radius, dist, tFrac;
00031
00032
00033
00034
00035
00036
00037 if ( NAV_CheckAhead( NPC, goal->r.currentOrigin, &trace, ( NPC->clipmask & ~CONTENTS_BODY )|CONTENTS_BOTCLIP ) )
00038 {
00039
00040 return qtrue;
00041 }
00042
00043 if (!FlyingCreature(NPC))
00044 {
00045
00046 if ( fabs( NPC->r.currentOrigin[2] - goal->r.currentOrigin[2] ) > 48 )
00047 return qfalse;
00048 }
00049
00050
00051 radius = ( NPC->r.maxs[0] > NPC->r.maxs[1] ) ? NPC->r.maxs[0] : NPC->r.maxs[1];
00052 dist = Distance( NPC->r.currentOrigin, goal->r.currentOrigin );
00053 tFrac = 1.0f - ( radius / dist );
00054
00055 if ( trace.fraction >= tFrac )
00056 return qtrue;
00057
00058
00059 if ( goal->flags & FL_NAVGOAL )
00060 {
00061
00062 if ( NAV_HitNavGoal( trace.endpos, NPC->r.mins, NPC->r.maxs, goal->r.currentOrigin, NPCInfo->goalRadius, FlyingCreature( NPC ) ) )
00063 {
00064
00065 return qtrue;
00066 }
00067 }
00068
00069 return qfalse;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078 ID_INLINE qboolean NPC_CheckCombatMove( void )
00079 {
00080
00081 if ( ( NPCInfo->goalEntity && NPC->enemy && NPCInfo->goalEntity == NPC->enemy ) || ( NPCInfo->combatMove ) )
00082 {
00083 return qtrue;
00084 }
00085
00086 if ( NPCInfo->goalEntity && NPCInfo->watchTarget )
00087 {
00088 if ( NPCInfo->goalEntity != NPCInfo->watchTarget )
00089 {
00090 return qtrue;
00091 }
00092 }
00093
00094 return qfalse;
00095 }
00096
00097
00098
00099
00100
00101
00102
00103 static void NPC_LadderMove( vec3_t dir )
00104 {
00105
00106
00107
00108
00109
00110 if ( ( dir[2] > 0 ) || ( dir[2] < 0 && NPC->client->ps.groundEntityNum == ENTITYNUM_NONE ) )
00111 {
00112
00113 ucmd.upmove = (dir[2] > 0) ? 127 : -127;
00114
00115
00116 ucmd.forwardmove = ucmd.rightmove = 0;
00117 }
00118 }
00119
00120
00121
00122
00123
00124
00125
00126 ID_INLINE qboolean NPC_GetMoveInformation( vec3_t dir, float *distance )
00127 {
00128
00129
00130
00131 if ( NPCInfo->goalEntity == NULL )
00132 return qfalse;
00133
00134
00135 VectorSubtract( NPCInfo->goalEntity->r.currentOrigin, NPC->r.currentOrigin, dir );
00136 *distance = VectorNormalize( dir );
00137
00138 VectorCopy( NPCInfo->goalEntity->r.currentOrigin, NPCInfo->blockedDest );
00139
00140 return qtrue;
00141 }
00142
00143
00144
00145
00146
00147
00148
00149 void NAV_GetLastMove( navInfo_t *info )
00150 {
00151 *info = frameNavInfo;
00152 }
00153
00154
00155
00156
00157
00158
00159
00160 qboolean NPC_GetMoveDirection( vec3_t out, float *distance )
00161 {
00162 vec3_t angles;
00163
00164
00165 memset( &frameNavInfo, 0, sizeof( frameNavInfo ) );
00166
00167
00168 if ( NPC_GetMoveInformation( frameNavInfo.direction, &frameNavInfo.distance ) == qfalse )
00169 return qfalse;
00170
00171
00172 *distance = frameNavInfo.distance;
00173
00174
00175 VectorCopy( frameNavInfo.direction, frameNavInfo.pathDirection );
00176
00177
00178 if ( NPC->watertype & CONTENTS_LADDER )
00179 {
00180 NPC_LadderMove( frameNavInfo.direction );
00181 return qtrue;
00182 }
00183
00184
00185 if ( NPC_ClearPathToGoal( frameNavInfo.direction, NPCInfo->goalEntity ) == qfalse )
00186 {
00187
00188 if ( NAV_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00189 {
00190
00191 vectoangles( frameNavInfo.direction, angles );
00192 NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] );
00193 VectorCopy( frameNavInfo.direction, out );
00194 *distance = frameNavInfo.distance;
00195 return qfalse;
00196 }
00197
00198 frameNavInfo.flags |= NIF_MACRO_NAV;
00199 }
00200
00201
00202 if ( NAV_AvoidCollision( NPC, NPCInfo->goalEntity, &frameNavInfo ) == qfalse )
00203 {
00204
00205
00206
00207
00208 if ( !(frameNavInfo.flags&NIF_MACRO_NAV) )
00209 {
00210
00211 if ( NAV_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00212 {
00213
00214 vectoangles( frameNavInfo.direction, angles );
00215 NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] );
00216 VectorCopy( frameNavInfo.direction, out );
00217 *distance = frameNavInfo.distance;
00218 return qfalse;
00219 }
00220
00221 frameNavInfo.flags |= NIF_MACRO_NAV;
00222 }
00223 }
00224
00225
00226 VectorCopy( frameNavInfo.direction, out );
00227 *distance = frameNavInfo.distance;
00228
00229 return qtrue;
00230 }
00231
00232
00233
00234
00235
00236
00237 extern int NAVNEW_MoveToGoal( gentity_t *self, navInfo_t *info );
00238 extern qboolean NAVNEW_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t *info, qboolean setBlockedInfo, int blockedMovesLimit );
00239 qboolean NPC_GetMoveDirectionAltRoute( vec3_t out, float *distance, qboolean tryStraight )
00240 {
00241 vec3_t angles;
00242
00243 NPCInfo->aiFlags &= ~NPCAI_BLOCKED;
00244
00245
00246 memset( &frameNavInfo, 0, sizeof( frameNavInfo ) );
00247
00248
00249 if ( NPC_GetMoveInformation( frameNavInfo.direction, &frameNavInfo.distance ) == qfalse )
00250 return qfalse;
00251
00252
00253 *distance = frameNavInfo.distance;
00254
00255
00256 VectorCopy( frameNavInfo.direction, frameNavInfo.pathDirection );
00257
00258
00259 if ( NPC->watertype & CONTENTS_LADDER )
00260 {
00261 NPC_LadderMove( frameNavInfo.direction );
00262 return qtrue;
00263 }
00264
00265
00266 if ( !tryStraight || NPC_ClearPathToGoal( frameNavInfo.direction, NPCInfo->goalEntity ) == qfalse )
00267 {
00268
00269 if ( NAVNEW_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00270 {
00271
00272 vectoangles( frameNavInfo.direction, angles );
00273 NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] );
00274 VectorCopy( frameNavInfo.direction, out );
00275 *distance = frameNavInfo.distance;
00276 return qfalse;
00277 }
00278
00279 frameNavInfo.flags |= NIF_MACRO_NAV;
00280 }
00281 else
00282 {
00283
00284 if ( d_altRoutes.integer )
00285 {
00286 navInfo_t tempInfo;
00287 memcpy( &tempInfo, &frameNavInfo, sizeof( tempInfo ) );
00288 if ( NAVNEW_AvoidCollision( NPC, NPCInfo->goalEntity, &tempInfo, qtrue, 5 ) == qfalse )
00289 {
00290
00291 if ( NAVNEW_MoveToGoal( NPC, &frameNavInfo ) == WAYPOINT_NONE )
00292 {
00293
00294 vectoangles( frameNavInfo.direction, angles );
00295 NPCInfo->desiredYaw = AngleNormalize360( angles[YAW] );
00296 VectorCopy( frameNavInfo.direction, out );
00297 *distance = frameNavInfo.distance;
00298 return qfalse;
00299 }
00300
00301 frameNavInfo.flags |= NIF_MACRO_NAV;
00302 }
00303 else
00304 {
00305 memcpy( &frameNavInfo, &tempInfo, sizeof( frameNavInfo ) );
00306 }
00307 }
00308 else
00309 {
00310 if ( NAVNEW_AvoidCollision( NPC, NPCInfo->goalEntity, &frameNavInfo, qtrue, 30 ) == qfalse )
00311 {
00312 return qfalse;
00313 }
00314 }
00315 }
00316
00317
00318 VectorCopy( frameNavInfo.direction, out );
00319 *distance = frameNavInfo.distance;
00320
00321 return qtrue;
00322 }
00323
00324 void G_UcmdMoveForDir( gentity_t *self, usercmd_t *cmd, vec3_t dir )
00325 {
00326 vec3_t forward, right;
00327 float fDot, rDot;
00328
00329 AngleVectors( self->r.currentAngles, forward, right, NULL );
00330
00331 dir[2] = 0;
00332 VectorNormalize( dir );
00333
00334 VectorCopy( dir, self->client->ps.moveDir );
00335
00336 fDot = DotProduct( forward, dir ) * 127.0f;
00337 rDot = DotProduct( right, dir ) * 127.0f;
00338
00339 if ( fDot > 127.0f )
00340 {
00341 fDot = 127.0f;
00342 }
00343 if ( fDot < -127.0f )
00344 {
00345 fDot = -127.0f;
00346 }
00347 if ( rDot > 127.0f )
00348 {
00349 rDot = 127.0f;
00350 }
00351 if ( rDot < -127.0f )
00352 {
00353 rDot = -127.0f;
00354 }
00355 cmd->forwardmove = floor(fDot);
00356 cmd->rightmove = floor(rDot);
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379 #if AI_TIMERS
00380 extern int navTime;
00381 #endif// AI_TIMERS
00382 qboolean NPC_MoveToGoal( qboolean tryStraight )
00383 {
00384 float distance;
00385 vec3_t dir;
00386
00387 #if AI_TIMERS
00388 int startTime = GetTime(0);
00389 #endif// AI_TIMERS
00390
00391 if ( PM_InKnockDown( &NPC->client->ps ) || ( ( NPC->s.legsAnim >= BOTH_PAIN1 ) && ( NPC->s.legsAnim <= BOTH_PAIN18 ) ) )
00392 {
00393 return qtrue;
00394 }
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 #if 1
00407 if ( NPC_GetMoveDirectionAltRoute( dir, &distance, tryStraight ) == qfalse )
00408 #else
00409 if ( NPC_GetMoveDirection( dir, &distance ) == qfalse )
00410 #endif
00411 return qfalse;
00412
00413 NPCInfo->distToGoal = distance;
00414
00415
00416 vectoangles( dir, NPCInfo->lastPathAngles );
00417 if ( (ucmd.buttons&BUTTON_WALKING) )
00418 {
00419 NPC->client->ps.speed = NPCInfo->stats.walkSpeed;
00420 }
00421 else
00422 {
00423 NPC->client->ps.speed = NPCInfo->stats.runSpeed;
00424 }
00425
00426
00427
00428 if ( NPC_CheckCombatMove() )
00429 {
00430 G_UcmdMoveForDir( NPC, &ucmd, dir );
00431 }
00432 else
00433 {
00434
00435 NPCInfo->desiredPitch = 0.0f;
00436 NPCInfo->desiredYaw = AngleNormalize360( NPCInfo->lastPathAngles[YAW] );
00437
00438
00439 if ( (NPC->client->ps.eFlags2&EF2_FLYING) )
00440 {
00441 NPCInfo->desiredPitch = AngleNormalize360( NPCInfo->lastPathAngles[PITCH] );
00442
00443 if ( dir[2] )
00444 {
00445 float scale = (dir[2] * distance);
00446 if ( scale > 64 )
00447 {
00448 scale = 64;
00449 }
00450 else if ( scale < -64 )
00451 {
00452 scale = -64;
00453 }
00454 NPC->client->ps.velocity[2] = scale;
00455
00456 }
00457 }
00458
00459
00460 ucmd.forwardmove = 127;
00461 }
00462
00463 #if AI_TIMERS
00464 navTime += GetTime( startTime );
00465 #endif// AI_TIMERS
00466 return qtrue;
00467 }
00468
00469
00470
00471
00472
00473
00474
00475
00476 qboolean NPC_SlideMoveToGoal( void )
00477 {
00478 float saveYaw = NPC->client->ps.viewangles[YAW];
00479 qboolean ret;
00480
00481 NPCInfo->combatMove = qtrue;
00482
00483 ret = NPC_MoveToGoal( qtrue );
00484
00485 NPCInfo->desiredYaw = saveYaw;
00486
00487 return ret;
00488 }
00489
00490
00491
00492
00493
00494
00495
00496
00497 void NPC_ApplyRoff(void)
00498 {
00499 BG_PlayerStateToEntityState( &NPC->client->ps, &NPC->s, qfalse );
00500
00501
00502
00503
00504 trap_LinkEntity(NPC);
00505 }