AI_Atst.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. #define MIN_MELEE_RANGE 640
  5. #define MIN_MELEE_RANGE_SQR ( MIN_MELEE_RANGE * MIN_MELEE_RANGE )
  6. #define MIN_DISTANCE 128
  7. #define MIN_DISTANCE_SQR ( MIN_DISTANCE * MIN_DISTANCE )
  8. #define TURN_OFF 0x00000100//G2SURFACEFLAG_NODESCENDANTS
  9. #define LEFT_ARM_HEALTH 40
  10. #define RIGHT_ARM_HEALTH 40
  11. /*
  12. -------------------------
  13. NPC_ATST_Precache
  14. -------------------------
  15. */
  16. void NPC_ATST_Precache(void)
  17. {
  18. G_SoundIndex( "sound/chars/atst/atst_damaged1" );
  19. G_SoundIndex( "sound/chars/atst/atst_damaged2" );
  20. RegisterItem( FindItemForWeapon( WP_ATST_MAIN )); //precache the weapon
  21. RegisterItem( FindItemForWeapon( WP_BOWCASTER )); //precache the weapon
  22. RegisterItem( FindItemForWeapon( WP_ROCKET_LAUNCHER )); //precache the weapon
  23. G_EffectIndex( "env/med_explode2" );
  24. // G_EffectIndex( "smaller_chunks" );
  25. G_EffectIndex( "blaster/smoke_bolton" );
  26. G_EffectIndex( "explosions/droidexplosion1" );
  27. }
  28. //-----------------------------------------------------------------
  29. static void ATST_PlayEffect( gentity_t *self, const int boltID, const char *fx )
  30. {
  31. if ( boltID >=0 && fx && fx[0] )
  32. {
  33. mdxaBone_t boltMatrix;
  34. vec3_t org, dir;
  35. gi.G2API_GetBoltMatrix( self->ghoul2, self->playerModel,
  36. boltID,
  37. &boltMatrix, self->currentAngles, self->currentOrigin, (cg.time?cg.time:level.time),
  38. NULL, self->s.modelScale );
  39. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, ORIGIN, org );
  40. gi.G2API_GiveMeVectorFromMatrix( boltMatrix, NEGATIVE_Y, dir );
  41. G_PlayEffect( fx, org, dir );
  42. }
  43. }
  44. /*
  45. -------------------------
  46. G_ATSTCheckPain
  47. Called by NPC's and player in an ATST
  48. -------------------------
  49. */
  50. void G_ATSTCheckPain( gentity_t *self, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc )
  51. {
  52. int newBolt;
  53. if ( rand() & 1 )
  54. {
  55. G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/atst/atst_damaged1" );
  56. }
  57. else
  58. {
  59. G_SoundOnEnt( self, CHAN_LESS_ATTEN, "sound/chars/atst/atst_damaged2" );
  60. }
  61. if ((hitLoc==HL_ARM_LT) && (self->locationDamage[HL_ARM_LT] > LEFT_ARM_HEALTH))
  62. {
  63. if (self->locationDamage[hitLoc] >= LEFT_ARM_HEALTH) // Blow it up?
  64. {
  65. newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash3" );
  66. if ( newBolt != -1 )
  67. {
  68. // G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt1, self->s.number);
  69. ATST_PlayEffect( self, self->genericBolt1, "env/med_explode2" );
  70. G_PlayEffect( G_EffectIndex("blaster/smoke_bolton"), self->playerModel, newBolt, self->s.number, point);
  71. }
  72. gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "head_light_blaster_cann", TURN_OFF );
  73. }
  74. }
  75. else if ((hitLoc==HL_ARM_RT) && (self->locationDamage[HL_ARM_RT] > RIGHT_ARM_HEALTH)) // Blow it up?
  76. {
  77. if (self->locationDamage[hitLoc] >= RIGHT_ARM_HEALTH)
  78. {
  79. newBolt = gi.G2API_AddBolt( &self->ghoul2[self->playerModel], "*flash4" );
  80. if ( newBolt != -1 )
  81. {
  82. // G_PlayEffect( "small_chunks", self->playerModel, self->genericBolt2, self->s.number);
  83. ATST_PlayEffect( self, self->genericBolt2, "env/med_explode2" );
  84. G_PlayEffect( G_EffectIndex("blaster/smoke_bolton"), self->playerModel, newBolt, self->s.number, point);
  85. }
  86. gi.G2API_SetSurfaceOnOff( &self->ghoul2[self->playerModel], "head_concussion_charger", TURN_OFF );
  87. }
  88. }
  89. }
  90. /*
  91. -------------------------
  92. NPC_ATST_Pain
  93. -------------------------
  94. */
  95. void NPC_ATST_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *other, const vec3_t point, int damage, int mod,int hitLoc )
  96. {
  97. G_ATSTCheckPain( self, other, point, damage, mod, hitLoc );
  98. NPC_Pain( self, inflictor, other, point, damage, mod );
  99. }
  100. /*
  101. -------------------------
  102. ATST_Hunt
  103. -------------------------`
  104. */
  105. void ATST_Hunt( qboolean visible, qboolean advance )
  106. {
  107. if ( NPCInfo->goalEntity == NULL )
  108. {//hunt
  109. NPCInfo->goalEntity = NPC->enemy;
  110. }
  111. NPCInfo->combatMove = qtrue;
  112. NPC_MoveToGoal( qtrue );
  113. }
  114. /*
  115. -------------------------
  116. ATST_Ranged
  117. -------------------------
  118. */
  119. void ATST_Ranged( qboolean visible, qboolean advance, qboolean altAttack )
  120. {
  121. if ( TIMER_Done( NPC, "atkDelay" ) && visible ) // Attack?
  122. {
  123. TIMER_Set( NPC, "atkDelay", Q_irand( 500, 3000 ) );
  124. if (altAttack)
  125. {
  126. ucmd.buttons |= BUTTON_ATTACK|BUTTON_ALT_ATTACK;
  127. }
  128. else
  129. {
  130. ucmd.buttons |= BUTTON_ATTACK;
  131. }
  132. }
  133. if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
  134. {
  135. ATST_Hunt( visible, advance );
  136. }
  137. }
  138. /*
  139. -------------------------
  140. ATST_Attack
  141. -------------------------
  142. */
  143. void ATST_Attack( void )
  144. {
  145. qboolean altAttack=qfalse;
  146. int blasterTest,chargerTest,weapon;
  147. if ( NPC_CheckEnemyExt() == qfalse )//!NPC->enemy )//
  148. {
  149. NPC->enemy = NULL;
  150. return;
  151. }
  152. NPC_FaceEnemy( qtrue );
  153. // Rate our distance to the target, and our visibilty
  154. float distance = (int) DistanceHorizontalSquared( NPC->currentOrigin, NPC->enemy->currentOrigin );
  155. distance_e distRate = ( distance > MIN_MELEE_RANGE_SQR ) ? DIST_LONG : DIST_MELEE;
  156. qboolean visible = NPC_ClearLOS( NPC->enemy );
  157. qboolean advance = (qboolean)(distance > MIN_DISTANCE_SQR);
  158. // If we cannot see our target, move to see it
  159. if ( visible == qfalse )
  160. {
  161. if ( NPCInfo->scriptFlags & SCF_CHASE_ENEMIES )
  162. {
  163. ATST_Hunt( visible, advance );
  164. return;
  165. }
  166. }
  167. // Decide what type of attack to do
  168. switch ( distRate )
  169. {
  170. case DIST_MELEE:
  171. NPC_ChangeWeapon( WP_ATST_MAIN );
  172. break;
  173. case DIST_LONG:
  174. NPC_ChangeWeapon( WP_ATST_SIDE );
  175. // See if the side weapons are there
  176. blasterTest = gi.G2API_GetSurfaceRenderStatus( &NPC->ghoul2[NPC->playerModel], "head_light_blaster_cann" );
  177. chargerTest = gi.G2API_GetSurfaceRenderStatus( &NPC->ghoul2[NPC->playerModel], "head_concussion_charger" );
  178. // It has both side weapons
  179. if (!(blasterTest & TURN_OFF) && !(chargerTest & TURN_OFF))
  180. {
  181. weapon = Q_irand( 0, 1); // 0 is blaster, 1 is charger (ALT SIDE)
  182. if (weapon) // Fire charger
  183. {
  184. altAttack = qtrue;
  185. }
  186. else
  187. {
  188. altAttack = qfalse;
  189. }
  190. }
  191. else if (!(blasterTest & TURN_OFF)) // Blaster is on
  192. {
  193. altAttack = qfalse;
  194. }
  195. else if (!(chargerTest & TURN_OFF)) // Blaster is on
  196. {
  197. altAttack = qtrue;
  198. }
  199. else
  200. {
  201. NPC_ChangeWeapon( WP_NONE );
  202. }
  203. break;
  204. }
  205. NPC_FaceEnemy( qtrue );
  206. ATST_Ranged( visible, advance,altAttack );
  207. }
  208. /*
  209. -------------------------
  210. ATST_Patrol
  211. -------------------------
  212. */
  213. void ATST_Patrol( void )
  214. {
  215. if ( NPC_CheckPlayerTeamStealth() )
  216. {
  217. NPC_UpdateAngles( qtrue, qtrue );
  218. return;
  219. }
  220. //If we have somewhere to go, then do that
  221. if (!NPC->enemy)
  222. {
  223. if ( UpdateGoal() )
  224. {
  225. ucmd.buttons |= BUTTON_WALKING;
  226. NPC_MoveToGoal( qtrue );
  227. NPC_UpdateAngles( qtrue, qtrue );
  228. }
  229. }
  230. }
  231. /*
  232. -------------------------
  233. ATST_Idle
  234. -------------------------
  235. */
  236. void ATST_Idle( void )
  237. {
  238. NPC_BSIdle();
  239. NPC_SetAnim( NPC, SETANIM_BOTH, BOTH_STAND1, SETANIM_FLAG_NORMAL );
  240. }
  241. /*
  242. -------------------------
  243. NPC_BSDroid_Default
  244. -------------------------
  245. */
  246. void NPC_BSATST_Default( void )
  247. {
  248. if ( NPC->enemy )
  249. {
  250. if( (NPCInfo->scriptFlags & SCF_CHASE_ENEMIES) )
  251. {
  252. NPCInfo->goalEntity = NPC->enemy;
  253. }
  254. ATST_Attack();
  255. }
  256. else if ( NPCInfo->scriptFlags & SCF_LOOK_FOR_ENEMIES )
  257. {
  258. ATST_Patrol();
  259. }
  260. else
  261. {
  262. ATST_Idle();
  263. }
  264. }