AI_Animal.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. // leave this line at the top of all AI_xxxx.cpp files for PCH reasons...
  2. #include "g_headers.h"
  3. #include "b_local.h"
  4. #include "..\Ratl\vector_vs.h"
  5. #define MAX_PACKS 10
  6. #define LEAVE_PACK_DISTANCE 1000
  7. #define JOIN_PACK_DISTANCE 800
  8. #define WANDER_RANGE 1000
  9. #define FRIGHTEN_DISTANCE 300
  10. extern qboolean G_PlayerSpawned( void );
  11. ratl::vector_vs<gentity_t*, MAX_PACKS> mPacks;
  12. ////////////////////////////////////////////////////////////////////////////////////////
  13. // Update The Packs, Delete Dead Leaders, Join / Split Packs, Find MY Leader
  14. ////////////////////////////////////////////////////////////////////////////////////////
  15. gentity_t* NPC_AnimalUpdateLeader(void)
  16. {
  17. // Find The Closest Pack Leader, Not Counting Myself
  18. //---------------------------------------------------
  19. gentity_t* closestLeader = 0;
  20. float closestDist = 0;
  21. int myLeaderNum = 0;
  22. for (int i=0; i<mPacks.size(); i++)
  23. {
  24. // Dump Dead Leaders
  25. //-------------------
  26. if (mPacks[i]==0 || mPacks[i]->health<=0)
  27. {
  28. if (mPacks[i]==NPC->client->leader)
  29. {
  30. NPC->client->leader = 0;
  31. }
  32. mPacks.erase_swap(i);
  33. if (i>=mPacks.size())
  34. {
  35. closestLeader = 0;
  36. break;
  37. }
  38. }
  39. // Don't Count Self
  40. //------------------
  41. if (mPacks[i]==NPC)
  42. {
  43. myLeaderNum = i;
  44. continue;
  45. }
  46. float Dist = Distance(mPacks[i]->currentOrigin, NPC->currentOrigin);
  47. if (!closestLeader || Dist<closestDist)
  48. {
  49. closestDist = Dist;
  50. closestLeader = mPacks[i];
  51. }
  52. }
  53. // In Joining Distance?
  54. //----------------------
  55. if (closestLeader && closestDist<JOIN_PACK_DISTANCE)
  56. {
  57. // Am I Already A Leader?
  58. //------------------------
  59. if (NPC->client->leader==NPC)
  60. {
  61. mPacks.erase_swap(myLeaderNum); // Erase Myself From The Leader List
  62. }
  63. // Join The Pack!
  64. //----------------
  65. NPC->client->leader = closestLeader;
  66. }
  67. // Do I Have A Leader?
  68. //---------------------
  69. if (NPC->client->leader)
  70. {
  71. // AM I A Leader?
  72. //----------------
  73. if (NPC->client->leader!=NPC)
  74. {
  75. // If Our Leader Is Dead, Clear Him Out
  76. if ( NPC->client->leader->health<=0 || NPC->client->leader->inuse == 0)
  77. {
  78. NPC->client->leader = 0;
  79. }
  80. // If My Leader Isn't His Own Leader, Then, Use His Leader
  81. //---------------------------------------------------------
  82. else if (NPC->client->leader->client->leader!=NPC->client->leader)
  83. {
  84. // Eh. Can this get more confusing?
  85. NPC->client->leader = NPC->client->leader->client->leader;
  86. }
  87. // If Our Leader Is Too Far Away, Clear Him Out
  88. //------------------------------------------------------
  89. else if ( Distance(NPC->client->leader->currentOrigin, NPC->currentOrigin)>LEAVE_PACK_DISTANCE)
  90. {
  91. NPC->client->leader = 0;
  92. }
  93. }
  94. }
  95. // If We Couldn't Find A Leader, Then Become One
  96. //-----------------------------------------------
  97. else if (!mPacks.full())
  98. {
  99. NPC->client->leader = NPC;
  100. mPacks.push_back(NPC);
  101. }
  102. return NPC->client->leader;
  103. }
  104. /*
  105. -------------------------
  106. NPC_BSAnimal_Default
  107. -------------------------
  108. */
  109. void NPC_BSAnimal_Default( void )
  110. {
  111. if (!NPC || !NPC->client)
  112. {
  113. return;
  114. }
  115. // Update Some Positions
  116. //-----------------------
  117. CVec3 CurrentLocation(NPC->currentOrigin);
  118. // Update The Leader
  119. //-------------------
  120. gentity_t* leader = NPC_AnimalUpdateLeader();
  121. // Select Closest Threat Location
  122. //--------------------------------
  123. CVec3 ThreatLocation(0,0,0);
  124. qboolean PlayerSpawned = G_PlayerSpawned();
  125. if ( PlayerSpawned )
  126. {//player is actually in the level now
  127. ThreatLocation = player->currentOrigin;
  128. }
  129. int alertEvent = NPC_CheckAlertEvents(qtrue, qtrue, -1, qfalse, AEL_MINOR, qfalse);
  130. if ( alertEvent >= 0 )
  131. {
  132. alertEvent_t *event = &level.alertEvents[alertEvent];
  133. if (event->owner!=NPC && Distance(event->position, CurrentLocation.v)<event->radius)
  134. {
  135. ThreatLocation = event->position;
  136. }
  137. }
  138. // float DistToThreat = CurrentLocation.Dist(ThreatLocation);
  139. // float DistFromHome = CurrentLocation.Dist(mHome);
  140. bool EvadeThreat = (level.time<NPCInfo->investigateSoundDebounceTime);
  141. bool CharmedDocile = (level.time<NPCInfo->confusionTime);
  142. bool CharmedApproach = (level.time<NPCInfo->charmedTime);
  143. // If Not Already Evading, Test To See If We Should "Know" About The Threat
  144. //--------------------------------------------------------------------------
  145. /* if (false && !EvadeThreat && PlayerSpawned && (DistToThreat<FRIGHTEN_DISTANCE))
  146. {
  147. CVec3 LookAim(NPC->currentAngles);
  148. LookAim.AngToVec();
  149. CVec3 MyPos(CurrentLocation);
  150. MyPos -= ThreatLocation;
  151. MyPos.SafeNorm();
  152. float DirectionSimilarity = MyPos.Dot(LookAim);
  153. if (fabsf(DirectionSimilarity)<0.8f)
  154. {
  155. EvadeThreat = true;
  156. NPCInfo->investigateSoundDebounceTime = level.time + Q_irand(0, 1000);
  157. VectorCopy(ThreatLocation.v, NPCInfo->investigateGoal);
  158. }
  159. }*/
  160. STEER::Activate(NPC);
  161. {
  162. // Charmed Approach - Walk TOWARD The Threat Location
  163. //----------------------------------------------------
  164. if (CharmedApproach)
  165. {
  166. NAV::GoTo(NPC, NPCInfo->investigateGoal);
  167. }
  168. // Charmed Docile - Stay Put
  169. //---------------------------
  170. else if (CharmedDocile)
  171. {
  172. NAV::ClearPath(NPC);
  173. STEER::Stop(NPC);
  174. }
  175. // Run Away From This Threat
  176. //---------------------------
  177. else if (EvadeThreat)
  178. {
  179. NAV::ClearPath(NPC);
  180. STEER::Flee(NPC, NPCInfo->investigateGoal);
  181. }
  182. // Normal Behavior
  183. //-----------------
  184. else
  185. {
  186. // Follow Our Pack Leader!
  187. //-------------------------
  188. if (leader && leader!=NPC)
  189. {
  190. float followDist = 100.0f;
  191. float curDist = Distance(NPC->currentOrigin, leader->followPos);
  192. // Update The Leader's Follow Position
  193. //-------------------------------------
  194. STEER::FollowLeader(NPC, leader, followDist);
  195. bool inSeekRange = (curDist<followDist*10.0f);
  196. bool onNbrPoints = (NAV::OnNeighboringPoints(NAV::GetNearestNode(NPC), leader->followPosWaypoint));
  197. bool leaderStop = ((level.time - leader->lastMoveTime)>500);
  198. // If Close Enough, Dump Any Existing Path
  199. //-----------------------------------------
  200. if (inSeekRange || onNbrPoints)
  201. {
  202. NAV::ClearPath(NPC);
  203. // If The Leader Isn't Moving, Stop
  204. //----------------------------------
  205. if (leaderStop)
  206. {
  207. STEER::Stop(NPC);
  208. }
  209. // Otherwise, Try To Get To The Follow Position
  210. //----------------------------------------------
  211. else
  212. {
  213. STEER::Seek(NPC, leader->followPos, fabsf(followDist)/2.0f/*slowing distance*/, 1.0f/*wight*/, leader->resultspeed);
  214. }
  215. }
  216. // Otherwise, Get A Path To The Follow Position
  217. //----------------------------------------------
  218. else
  219. {
  220. NAV::GoTo(NPC, leader->followPosWaypoint);
  221. }
  222. STEER::Separation(NPC, 4.0f);
  223. STEER::AvoidCollisions(NPC, leader);
  224. }
  225. // Leader AI - Basically Wander
  226. //------------------------------
  227. else
  228. {
  229. // Are We Doing A Path?
  230. //----------------------
  231. bool HasPath = NAV::HasPath(NPC);
  232. if (HasPath)
  233. {
  234. HasPath = NAV::UpdatePath(NPC);
  235. if (HasPath)
  236. {
  237. STEER::Path(NPC); // Follow The Path
  238. STEER::AvoidCollisions(NPC);
  239. }
  240. }
  241. if (!HasPath)
  242. {
  243. // If Debounce Time Has Expired, Choose A New Sub State
  244. //------------------------------------------------------
  245. if (NPCInfo->investigateDebounceTime<level.time)
  246. {
  247. // Clear Out Flags From The Previous Substate
  248. //--------------------------------------------
  249. NPCInfo->aiFlags &= ~NPCAI_OFF_PATH;
  250. NPCInfo->aiFlags &= ~NPCAI_WALKING;
  251. // Pick Another Spot
  252. //-------------------
  253. int NEXTSUBSTATE = Q_irand(0, 10);
  254. bool RandomPathNode = (NEXTSUBSTATE<8); //(NEXTSUBSTATE<9);
  255. bool PathlessWander = (NEXTSUBSTATE<9); //false;
  256. // Random Path Node
  257. //------------------
  258. if (RandomPathNode)
  259. {
  260. // Sometimes, Walk
  261. //-----------------
  262. if (Q_irand(0, 1)==0)
  263. {
  264. NPCInfo->aiFlags |= NPCAI_WALKING;
  265. }
  266. NPCInfo->investigateDebounceTime = level.time + Q_irand(3000, 10000);
  267. NAV::FindPath(NPC, NAV::ChooseRandomNeighbor(NAV::GetNearestNode(NPC)));//, mHome.v, WANDER_RANGE));
  268. }
  269. // Pathless Wandering
  270. //--------------------
  271. else if (PathlessWander)
  272. {
  273. // Sometimes, Walk
  274. //-----------------
  275. if (Q_irand(0, 1)==0)
  276. {
  277. NPCInfo->aiFlags |= NPCAI_WALKING;
  278. }
  279. NPCInfo->investigateDebounceTime = level.time + Q_irand(3000, 10000);
  280. NPCInfo->aiFlags |= NPCAI_OFF_PATH;
  281. }
  282. // Just Stand Here
  283. //-----------------
  284. else
  285. {
  286. NPCInfo->investigateDebounceTime = level.time + Q_irand(2000, 6000);
  287. //NPC_SetAnim(NPC, SETANIM_BOTH, ((Q_irand(0, 1)==0)?(BOTH_GUARD_LOOKAROUND1):(BOTH_GUARD_IDLE1)), SETANIM_FLAG_NORMAL);
  288. }
  289. }
  290. // Ok, So We Don't Have A Path, And Debounce Time Is Still Active, So We Are Either Wandering Or Looking Around
  291. //--------------------------------------------------------------------------------------------------------------
  292. else
  293. {
  294. // if (DistFromHome>(WANDER_RANGE))
  295. // {
  296. // STEER::Seek(NPC, mHome);
  297. // }
  298. // else
  299. {
  300. if (NPCInfo->aiFlags & NPCAI_OFF_PATH)
  301. {
  302. STEER::Wander(NPC);
  303. STEER::AvoidCollisions(NPC);
  304. }
  305. else
  306. {
  307. STEER::Stop(NPC);
  308. }
  309. }
  310. }
  311. }
  312. }
  313. }
  314. }
  315. STEER::DeActivate(NPC, &ucmd);
  316. NPC_UpdateAngles( qtrue, qtrue );
  317. }