home *** CD-ROM | disk | FTP | other *** search
/ Gambler 19 / GAMBLERCD19.BIN / UTILS / 3D / BRONIE / DUAL_LAU.ZIP / src / m_tank.c < prev    next >
C/C++ Source or Header  |  1998-01-13  |  19KB  |  834 lines

  1. /*
  2. ==============================================================================
  3.  
  4. TANK
  5.  
  6. ==============================================================================
  7. */
  8.  
  9. #include "g_local.h"
  10. #include "m_tank.h"
  11.  
  12.  
  13. void tank_refire_rocket (edict_t *self);
  14. void tank_doattack_rocket (edict_t *self);
  15. void tank_reattack_blaster (edict_t *self);
  16.  
  17. static int    sound_thud;
  18. static int    sound_pain;
  19. static int    sound_idle;
  20. static int    sound_die;
  21. static int    sound_step;
  22. static int    sound_sight;
  23. static int    sound_windup;
  24. static int    sound_strike;
  25.  
  26. //
  27. // misc
  28. //
  29.  
  30. void tank_sight (edict_t *self, edict_t *other)
  31. {
  32.     gi.sound (self, CHAN_VOICE, sound_sight, 1, ATTN_NORM, 0);
  33. }
  34.  
  35.  
  36. void tank_footstep (edict_t *self)
  37. {
  38.     gi.sound (self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
  39. }
  40.  
  41. void tank_thud (edict_t *self)
  42. {
  43.     gi.sound (self, CHAN_BODY, sound_thud, 1, ATTN_NORM, 0);
  44. }
  45.  
  46. void tank_windup (edict_t *self)
  47. {
  48.     gi.sound (self, CHAN_WEAPON, sound_windup, 1, ATTN_NORM, 0);
  49. }
  50.  
  51. void tank_idle (edict_t *self)
  52. {
  53.     gi.sound (self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
  54. }
  55.  
  56.  
  57. //
  58. // stand
  59. //
  60.  
  61. mframe_t tank_frames_stand []=
  62. {
  63.     ai_stand, 0, NULL,
  64.     ai_stand, 0, NULL,
  65.     ai_stand, 0, NULL,
  66.     ai_stand, 0, NULL,
  67.     ai_stand, 0, NULL,
  68.     ai_stand, 0, NULL,
  69.     ai_stand, 0, NULL,
  70.     ai_stand, 0, NULL,
  71.     ai_stand, 0, NULL,
  72.     ai_stand, 0, NULL,
  73.     ai_stand, 0, NULL,
  74.     ai_stand, 0, NULL,
  75.     ai_stand, 0, NULL,
  76.     ai_stand, 0, NULL,
  77.     ai_stand, 0, NULL,
  78.     ai_stand, 0, NULL,
  79.     ai_stand, 0, NULL,
  80.     ai_stand, 0, NULL,
  81.     ai_stand, 0, NULL,
  82.     ai_stand, 0, NULL,
  83.     ai_stand, 0, NULL,
  84.     ai_stand, 0, NULL,
  85.     ai_stand, 0, NULL,
  86.     ai_stand, 0, NULL,
  87.     ai_stand, 0, NULL,
  88.     ai_stand, 0, NULL,
  89.     ai_stand, 0, NULL,
  90.     ai_stand, 0, NULL,
  91.     ai_stand, 0, NULL,
  92.     ai_stand, 0, NULL
  93. };
  94. mmove_t    tank_move_stand = {FRAME_stand01, FRAME_stand30, tank_frames_stand, NULL};
  95.     
  96. void tank_stand (edict_t *self)
  97. {
  98.     self->monsterinfo.currentmove = &tank_move_stand;
  99. }
  100.  
  101.  
  102. //
  103. // walk
  104. //
  105.  
  106. void tank_walk (edict_t *self);
  107.  
  108. mframe_t tank_frames_start_walk [] =
  109. {
  110.     ai_walk,  0, NULL,
  111.     ai_walk,  6, NULL,
  112.     ai_walk,  6, NULL,
  113.     ai_walk, 11, tank_footstep
  114. };
  115. mmove_t    tank_move_start_walk = {FRAME_walk01, FRAME_walk04, tank_frames_start_walk, tank_walk};
  116.  
  117. mframe_t tank_frames_walk [] =
  118. {
  119.     ai_walk, 4,    NULL,
  120.     ai_walk, 5,    NULL,
  121.     ai_walk, 3,    NULL,
  122.     ai_walk, 2,    NULL,
  123.     ai_walk, 5,    NULL,
  124.     ai_walk, 5,    NULL,
  125.     ai_walk, 4,    NULL,
  126.     ai_walk, 4,    tank_footstep,
  127.     ai_walk, 3,    NULL,
  128.     ai_walk, 5,    NULL,
  129.     ai_walk, 4,    NULL,
  130.     ai_walk, 5,    NULL,
  131.     ai_walk, 7,    NULL,
  132.     ai_walk, 7,    NULL,
  133.     ai_walk, 6,    NULL,
  134.     ai_walk, 6,    tank_footstep
  135. };
  136. mmove_t    tank_move_walk = {FRAME_walk05, FRAME_walk20, tank_frames_walk, NULL};
  137.  
  138. mframe_t tank_frames_stop_walk [] =
  139. {
  140.     ai_walk,  3, NULL,
  141.     ai_walk,  3, NULL,
  142.     ai_walk,  2, NULL,
  143.     ai_walk,  2, NULL,
  144.     ai_walk,  4, tank_footstep
  145. };
  146. mmove_t    tank_move_stop_walk = {FRAME_walk21, FRAME_walk25, tank_frames_stop_walk, tank_stand};
  147.  
  148. void tank_walk (edict_t *self)
  149. {
  150.         self->monsterinfo.currentmove = &tank_move_walk;
  151. }
  152.  
  153.  
  154. //
  155. // run
  156. //
  157.  
  158. void tank_run (edict_t *self);
  159.  
  160. mframe_t tank_frames_start_run [] =
  161. {
  162.     ai_run,  0, NULL,
  163.     ai_run,  6, NULL,
  164.     ai_run,  6, NULL,
  165.     ai_run, 11, tank_footstep
  166. };
  167. mmove_t    tank_move_start_run = {FRAME_walk01, FRAME_walk04, tank_frames_start_run, tank_run};
  168.  
  169. mframe_t tank_frames_run [] =
  170. {
  171.     ai_run, 4,    NULL,
  172.     ai_run, 5,    NULL,
  173.     ai_run, 3,    NULL,
  174.     ai_run, 2,    NULL,
  175.     ai_run, 5,    NULL,
  176.     ai_run, 5,    NULL,
  177.     ai_run, 4,    NULL,
  178.     ai_run, 4,    tank_footstep,
  179.     ai_run, 3,    NULL,
  180.     ai_run, 5,    NULL,
  181.     ai_run, 4,    NULL,
  182.     ai_run, 5,    NULL,
  183.     ai_run, 7,    NULL,
  184.     ai_run, 7,    NULL,
  185.     ai_run, 6,    NULL,
  186.     ai_run, 6,    tank_footstep
  187. };
  188. mmove_t    tank_move_run = {FRAME_walk05, FRAME_walk20, tank_frames_run, NULL};
  189.  
  190. mframe_t tank_frames_stop_run [] =
  191. {
  192.     ai_run,  3, NULL,
  193.     ai_run,  3, NULL,
  194.     ai_run,  2, NULL,
  195.     ai_run,  2, NULL,
  196.     ai_run,  4, tank_footstep
  197. };
  198. mmove_t    tank_move_stop_run = {FRAME_walk21, FRAME_walk25, tank_frames_stop_run, tank_walk};
  199.  
  200. void tank_run (edict_t *self)
  201. {
  202.     if (self->enemy && self->enemy->client)
  203.         self->monsterinfo.aiflags |= AI_BRUTAL;
  204.     else
  205.         self->monsterinfo.aiflags &= ~AI_BRUTAL;
  206.  
  207.     if (self->monsterinfo.aiflags & AI_STAND_GROUND)
  208.     {
  209.         self->monsterinfo.currentmove = &tank_move_stand;
  210.         return;
  211.     }
  212.  
  213.     if (self->monsterinfo.currentmove == &tank_move_walk ||
  214.         self->monsterinfo.currentmove == &tank_move_start_run)
  215.     {
  216.         self->monsterinfo.currentmove = &tank_move_run;
  217.     }
  218.     else
  219.     {
  220.         self->monsterinfo.currentmove = &tank_move_start_run;
  221.     }
  222. }
  223.  
  224. //
  225. // pain
  226. //
  227.  
  228. mframe_t tank_frames_pain1 [] =
  229. {
  230.     ai_move, 0, NULL,
  231.     ai_move, 0, NULL,
  232.     ai_move, 0, NULL,
  233.     ai_move, 0, NULL
  234. };
  235. mmove_t tank_move_pain1 = {FRAME_pain101, FRAME_pain104, tank_frames_pain1, tank_run};
  236.  
  237. mframe_t tank_frames_pain2 [] =
  238. {
  239.     ai_move, 0, NULL,
  240.     ai_move, 0, NULL,
  241.     ai_move, 0, NULL,
  242.     ai_move, 0, NULL,
  243.     ai_move, 0, NULL
  244. };
  245. mmove_t tank_move_pain2 = {FRAME_pain201, FRAME_pain205, tank_frames_pain2, tank_run};
  246.  
  247. mframe_t tank_frames_pain3 [] =
  248. {
  249.     ai_move, -7, NULL,
  250.     ai_move, 0,  NULL,
  251.     ai_move, 0,  NULL,
  252.     ai_move, 0,  NULL,
  253.     ai_move, 2,  NULL,
  254.     ai_move, 0,  NULL,
  255.     ai_move, 0,  NULL,
  256.     ai_move, 3,  NULL,
  257.     ai_move, 0,  NULL,
  258.     ai_move, 2,  NULL,
  259.     ai_move, 0,  NULL,
  260.     ai_move, 0,  NULL,
  261.     ai_move, 0,  NULL,
  262.     ai_move, 0,  NULL,
  263.     ai_move, 0,  NULL,
  264.     ai_move, 0,  tank_footstep
  265. };
  266. mmove_t    tank_move_pain3 = {FRAME_pain301, FRAME_pain316, tank_frames_pain3, tank_run};
  267.  
  268.  
  269. void tank_pain (edict_t *self, edict_t *other, float kick, int damage)
  270. {
  271.     if (self->health < (self->max_health / 2))
  272.             self->s.skinnum |= 1;
  273.  
  274.     if (damage <= 10)
  275.         return;
  276.  
  277.     if (level.time < self->pain_debounce_time)
  278.             return;
  279.  
  280.     if (damage <= 30)
  281.         if (random() > 0.2)
  282.             return;
  283.     
  284.     // If hard or nightmare, don't go into pain while attacking
  285.     if ( skill->value >= 2)
  286.     {
  287.         if ( (self->s.frame >= FRAME_attak301) && (self->s.frame <= FRAME_attak330) )
  288.             return;
  289.         if ( (self->s.frame >= FRAME_attak101) && (self->s.frame <= FRAME_attak116) )
  290.             return;
  291.     }
  292.  
  293.     self->pain_debounce_time = level.time + 3;
  294.     gi.sound (self, CHAN_VOICE, sound_pain, 1, ATTN_NORM, 0);
  295.  
  296.     if (damage <= 30)
  297.         self->monsterinfo.currentmove = &tank_move_pain1;
  298.     else if (damage <= 60)
  299.         self->monsterinfo.currentmove = &tank_move_pain2;
  300.     else
  301.         self->monsterinfo.currentmove = &tank_move_pain3;
  302. }
  303.  
  304.  
  305. //
  306. // attacks
  307. //
  308.  
  309. void TankBlaster (edict_t *self)
  310. {
  311.     vec3_t    forward, right;
  312.     vec3_t    start;
  313.     vec3_t    end;
  314.     vec3_t    dir;
  315.     int        flash_number;
  316.  
  317.     if (self->s.frame == FRAME_attak110)
  318.         flash_number = MZ2_TANK_BLASTER_1;
  319.     else if (self->s.frame == FRAME_attak113)
  320.         flash_number = MZ2_TANK_BLASTER_2;
  321.     else // (self->s.frame == FRAME_attak116)
  322.         flash_number = MZ2_TANK_BLASTER_3;
  323.  
  324.     AngleVectors (self->s.angles, forward, right, NULL);
  325.     G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  326.  
  327.     VectorCopy (self->enemy->s.origin, end);
  328.     end[2] += self->enemy->viewheight;
  329.     VectorSubtract (end, start, dir);
  330.  
  331.     monster_fire_blaster (self, start, dir, 30, 800, flash_number, EF_BLASTER);
  332. }    
  333.  
  334. void TankStrike (edict_t *self)
  335. {
  336.     gi.sound (self, CHAN_WEAPON, sound_strike, 1, ATTN_NORM, 0);
  337. }    
  338.  
  339. void TankRocket (edict_t *self)
  340. {
  341.     vec3_t    forward, right;
  342.     vec3_t    start;
  343.     vec3_t    dir;
  344.     vec3_t    vec;
  345.     int        flash_number;
  346.  
  347.     if (self->s.frame == FRAME_attak324)
  348.         flash_number = MZ2_TANK_ROCKET_1;
  349.     else if (self->s.frame == FRAME_attak327)
  350.         flash_number = MZ2_TANK_ROCKET_2;
  351.     else // (self->s.frame == FRAME_attak330)
  352.         flash_number = MZ2_TANK_ROCKET_3;
  353.  
  354.     AngleVectors (self->s.angles, forward, right, NULL);
  355.     G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  356.  
  357.     VectorCopy (self->enemy->s.origin, vec);
  358.     vec[2] += self->enemy->viewheight;
  359.     VectorSubtract (vec, start, dir);
  360.     VectorNormalize (dir);
  361.  
  362.     monster_fire_rocket (self, start, dir, 50, 550, flash_number);
  363. }    
  364.  
  365. void TankMachineGun (edict_t *self)
  366. {
  367.     vec3_t    dir;
  368.     vec3_t    vec;
  369.     vec3_t    start;
  370.     vec3_t    forward, right;
  371.     int        flash_number;
  372.  
  373.     flash_number = MZ2_TANK_MACHINEGUN_1 + (self->s.frame - FRAME_attak406);
  374.  
  375.     AngleVectors (self->s.angles, forward, right, NULL);
  376.     G_ProjectSource (self->s.origin, monster_flash_offset[flash_number], forward, right, start);
  377.  
  378.     if (self->enemy)
  379.     {
  380.         VectorCopy (self->enemy->s.origin, vec);
  381.         vec[2] += self->enemy->viewheight;
  382.         VectorSubtract (vec, start, vec);
  383.         vectoangles (vec, vec);
  384.         dir[0] = vec[0];
  385.     }
  386.     else
  387.     {
  388.         dir[0] = 0;
  389.     }
  390.     if (self->s.frame <= FRAME_attak415)
  391.         dir[1] = self->s.angles[1] - 8 * (self->s.frame - FRAME_attak411);
  392.     else
  393.         dir[1] = self->s.angles[1] + 8 * (self->s.frame - FRAME_attak419);
  394.     dir[2] = 0;
  395.  
  396.     AngleVectors (dir, forward, NULL, NULL);
  397.  
  398.     monster_fire_bullet (self, start, forward, 20, 4, DEFAULT_BULLET_HSPREAD, DEFAULT_BULLET_VSPREAD, flash_number);
  399. }    
  400.  
  401.  
  402. mframe_t tank_frames_attack_blast [] =
  403. {
  404.     ai_charge, 0,    NULL,
  405.     ai_charge, 0,    NULL,
  406.     ai_charge, 0,    NULL,
  407.     ai_charge, 0,    NULL,
  408.     ai_charge, -1,    NULL,
  409.     ai_charge, -2,    NULL,
  410.     ai_charge, -1,    NULL,
  411.     ai_charge, -1,    NULL,
  412.     ai_charge, 0,    NULL,
  413.     ai_charge, 0,    TankBlaster,        // 10
  414.     ai_charge, 0,    NULL,
  415.     ai_charge, 0,    NULL,
  416.     ai_charge, 0,    TankBlaster,
  417.     ai_charge, 0,    NULL,
  418.     ai_charge, 0,    NULL,
  419.     ai_charge, 0,    TankBlaster            // 16
  420. };
  421. mmove_t tank_move_attack_blast = {FRAME_attak101, FRAME_attak116, tank_frames_attack_blast, tank_reattack_blaster};
  422.  
  423. mframe_t tank_frames_reattack_blast [] =
  424. {
  425.     ai_charge, 0,    NULL,
  426.     ai_charge, 0,    NULL,
  427.     ai_charge, 0,    TankBlaster,
  428.     ai_charge, 0,    NULL,
  429.     ai_charge, 0,    NULL,
  430.     ai_charge, 0,    TankBlaster            // 16
  431. };
  432. mmove_t tank_move_reattack_blast = {FRAME_attak111, FRAME_attak116, tank_frames_reattack_blast, tank_reattack_blaster};
  433.  
  434. mframe_t tank_frames_attack_post_blast [] =    
  435. {
  436.     ai_move, 0,        NULL,                // 17
  437.     ai_move, 0,        NULL,
  438.     ai_move, 2,        NULL,
  439.     ai_move, 3,        NULL,
  440.     ai_move, 2,        NULL,
  441.     ai_move, -2,    tank_footstep        // 22
  442. };
  443. mmove_t tank_move_attack_post_blast = {FRAME_attak117, FRAME_attak122, tank_frames_attack_post_blast, tank_run};
  444.  
  445. void tank_reattack_blaster (edict_t *self)
  446. {
  447.     if (skill->value >= 2)
  448.         if (visible (self, self->enemy))
  449.             if (self->enemy->health > 0)
  450.                 if (random() <= 0.6)
  451.                 {
  452.                     self->monsterinfo.currentmove = &tank_move_reattack_blast;
  453.                     return;
  454.                 }
  455.     self->monsterinfo.currentmove = &tank_move_attack_post_blast;
  456. }
  457.  
  458.  
  459. void tank_poststrike (edict_t *self)
  460. {
  461.     self->enemy = NULL;
  462.     tank_run (self);
  463. }
  464.  
  465. mframe_t tank_frames_attack_strike [] =
  466. {
  467.     ai_move, 3,   NULL,
  468.     ai_move, 2,   NULL,
  469.     ai_move, 2,   NULL,
  470.     ai_move, 1,   NULL,
  471.     ai_move, 6,   NULL,
  472.     ai_move, 7,   NULL,
  473.     ai_move, 9,   tank_footstep,
  474.     ai_move, 2,   NULL,
  475.     ai_move, 1,   NULL,
  476.     ai_move, 2,   NULL,
  477.     ai_move, 2,   tank_footstep,
  478.     ai_move, 2,   NULL,
  479.     ai_move, 0,   NULL,
  480.     ai_move, 0,   NULL,
  481.     ai_move, 0,   NULL,
  482.     ai_move, 0,   NULL,
  483.     ai_move, -2,  NULL,
  484.     ai_move, -2,  NULL,
  485.     ai_move, 0,   tank_windup,
  486.     ai_move, 0,   NULL,
  487.     ai_move, 0,   NULL,
  488.     ai_move, 0,   NULL,
  489.     ai_move, 0,   NULL,
  490.     ai_move, 0,   NULL,
  491.     ai_move, 0,   NULL,
  492.     ai_move, 0,   TankStrike,
  493.     ai_move, 0,   NULL,
  494.     ai_move, -1,  NULL,
  495.     ai_move, -1,  NULL,
  496.     ai_move, -1,  NULL,
  497.     ai_move, -1,  NULL,
  498.     ai_move, -1,  NULL,
  499.     ai_move, -3,  NULL,
  500.     ai_move, -10, NULL,
  501.     ai_move, -10, NULL,
  502.     ai_move, -2,  NULL,
  503.     ai_move, -3,  NULL,
  504.     ai_move, -2,  tank_footstep
  505. };
  506. mmove_t tank_move_attack_strike = {FRAME_attak201, FRAME_attak238, tank_frames_attack_strike, tank_poststrike};
  507.  
  508. mframe_t tank_frames_attack_pre_rocket [] =
  509. {
  510.     ai_charge, 0,  NULL,
  511.     ai_charge, 0,  NULL,
  512.     ai_charge, 0,  NULL,
  513.     ai_charge, 0,  NULL,
  514.     ai_charge, 0,  NULL,
  515.     ai_charge, 0,  NULL,
  516.     ai_charge, 0,  NULL,
  517.     ai_charge, 0,  NULL,
  518.     ai_charge, 0,  NULL,
  519.     ai_charge, 0,  NULL,            // 10
  520.  
  521.     ai_charge, 0,  NULL,
  522.     ai_charge, 1,  NULL,
  523.     ai_charge, 2,  NULL,
  524.     ai_charge, 7,  NULL,
  525.     ai_charge, 7,  NULL,
  526.     ai_charge, 7,  tank_footstep,
  527.     ai_charge, 0,  NULL,
  528.     ai_charge, 0,  NULL,
  529.     ai_charge, 0,  NULL,
  530.     ai_charge, 0,  NULL,            // 20
  531.  
  532.     ai_charge, -3, NULL
  533. };
  534. mmove_t tank_move_attack_pre_rocket = {FRAME_attak301, FRAME_attak321, tank_frames_attack_pre_rocket, tank_doattack_rocket};
  535.  
  536. mframe_t tank_frames_attack_fire_rocket [] =
  537. {
  538.     ai_charge, -3, NULL,            // Loop Start    22 
  539.     ai_charge, 0,  NULL,
  540.     ai_charge, 0,  TankRocket,        // 24
  541.     ai_charge, 0,  NULL,
  542.     ai_charge, 0,  NULL,
  543.     ai_charge, 0,  TankRocket,
  544.     ai_charge, 0,  NULL,
  545.     ai_charge, 0,  NULL,
  546.     ai_charge, -1, TankRocket        // 30    Loop End
  547. };
  548. mmove_t tank_move_attack_fire_rocket = {FRAME_attak322, FRAME_attak330, tank_frames_attack_fire_rocket, tank_refire_rocket};
  549.  
  550. mframe_t tank_frames_attack_post_rocket [] =
  551. {    
  552.     ai_charge, 0,  NULL,            // 31
  553.     ai_charge, -1, NULL,
  554.     ai_charge, -1, NULL,
  555.     ai_charge, 0,  NULL,
  556.     ai_charge, 2,  NULL,
  557.     ai_charge, 3,  NULL,
  558.     ai_charge, 4,  NULL,
  559.     ai_charge, 2,  NULL,
  560.     ai_charge, 0,  NULL,
  561.     ai_charge, 0,  NULL,            // 40
  562.  
  563.     ai_charge, 0,  NULL,
  564.     ai_charge, -9, NULL,
  565.     ai_charge, -8, NULL,
  566.     ai_charge, -7, NULL,
  567.     ai_charge, -1, NULL,
  568.     ai_charge, -1, tank_footstep,
  569.     ai_charge, 0,  NULL,
  570.     ai_charge, 0,  NULL,
  571.     ai_charge, 0,  NULL,
  572.     ai_charge, 0,  NULL,            // 50
  573.  
  574.     ai_charge, 0,  NULL,
  575.     ai_charge, 0,  NULL,
  576.     ai_charge, 0,  NULL
  577. };
  578. mmove_t tank_move_attack_post_rocket = {FRAME_attak331, FRAME_attak353, tank_frames_attack_post_rocket, tank_run};
  579.  
  580. mframe_t tank_frames_attack_chain [] =
  581. {
  582.     ai_charge, 0, NULL,
  583.     ai_charge, 0, NULL,
  584.     ai_charge, 0, NULL,
  585.     ai_charge, 0, NULL,
  586.     ai_charge, 0, NULL,
  587.     NULL,      0, TankMachineGun,
  588.     NULL,      0, TankMachineGun,
  589.     NULL,      0, TankMachineGun,
  590.     NULL,      0, TankMachineGun,
  591.     NULL,      0, TankMachineGun,
  592.     NULL,      0, TankMachineGun,
  593.     NULL,      0, TankMachineGun,
  594.     NULL,      0, TankMachineGun,
  595.     NULL,      0, TankMachineGun,
  596.     NULL,      0, TankMachineGun,
  597.     NULL,      0, TankMachineGun,
  598.     NULL,      0, TankMachineGun,
  599.     NULL,      0, TankMachineGun,
  600.     NULL,      0, TankMachineGun,
  601.     NULL,      0, TankMachineGun,
  602.     NULL,      0, TankMachineGun,
  603.     NULL,      0, TankMachineGun,
  604.     NULL,      0, TankMachineGun,
  605.     NULL,      0, TankMachineGun,
  606.     ai_charge, 0, NULL,
  607.     ai_charge, 0, NULL,
  608.     ai_charge, 0, NULL,
  609.     ai_charge, 0, NULL,
  610.     ai_charge, 0, NULL
  611. };
  612. mmove_t tank_move_attack_chain = {FRAME_attak401, FRAME_attak429, tank_frames_attack_chain, tank_run};
  613.  
  614. void tank_refire_rocket (edict_t *self)
  615. {
  616.     // Only on hard or nightmare
  617.     if ( skill->value >= 2 )
  618.         if (self->enemy->health > 0)
  619.             if (visible(self, self->enemy) )
  620.                 if (random() <= 0.4)
  621.                 {
  622.                     self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
  623.                     return;
  624.                 }
  625.     self->monsterinfo.currentmove = &tank_move_attack_post_rocket;
  626. }
  627.  
  628. void tank_doattack_rocket (edict_t *self)
  629. {
  630.     self->monsterinfo.currentmove = &tank_move_attack_fire_rocket;
  631. }
  632.  
  633. void tank_attack(edict_t *self)
  634. {
  635.     vec3_t    vec;
  636.     float    range;
  637.     float    r;
  638.  
  639.     if (self->enemy->health < 0)
  640.     {
  641.         self->monsterinfo.currentmove = &tank_move_attack_strike;
  642.         self->monsterinfo.aiflags &= ~AI_BRUTAL;
  643.         return;
  644.     }
  645.  
  646.     VectorSubtract (self->enemy->s.origin, self->s.origin, vec);
  647.     range = VectorLength (vec);
  648.  
  649.     r = random();
  650.  
  651.     if (range <= 125)
  652.     {
  653.         if (r < 0.4)
  654.             self->monsterinfo.currentmove = &tank_move_attack_chain;
  655.         else 
  656.             self->monsterinfo.currentmove = &tank_move_attack_blast;
  657.     }
  658.     else if (range <= 250)
  659.     {
  660.         if (r < 0.5)
  661.             self->monsterinfo.currentmove = &tank_move_attack_chain;
  662.         else
  663.             self->monsterinfo.currentmove = &tank_move_attack_blast;
  664.     }
  665.     else
  666.     {
  667.         if (r < 0.33)
  668.             self->monsterinfo.currentmove = &tank_move_attack_chain;
  669.         else if (r < 0.66)
  670.         {
  671.             self->monsterinfo.currentmove = &tank_move_attack_pre_rocket;
  672.             self->pain_debounce_time = level.time + 5.0;    // no pain for a while
  673.         }
  674.         else
  675.             self->monsterinfo.currentmove = &tank_move_attack_blast;
  676.     }
  677. }
  678.  
  679.  
  680. //
  681. // death
  682. //
  683.  
  684. void tank_dead (edict_t *self)
  685. {
  686.     VectorSet (self->mins, -16, -16, -16);
  687.     VectorSet (self->maxs, 16, 16, -0);
  688.     self->movetype = MOVETYPE_TOSS;
  689.     self->nextthink = 0;
  690.     gi.linkentity (self);
  691. }
  692.  
  693. mframe_t tank_frames_death1 [] =
  694. {
  695.     ai_move, -7,  NULL,
  696.     ai_move, -2,  NULL,
  697.     ai_move, -2,  NULL,
  698.     ai_move, 1,   NULL,
  699.     ai_move, 3,   NULL,
  700.     ai_move, 6,   NULL,
  701.     ai_move, 1,   NULL,
  702.     ai_move, 1,   NULL,
  703.     ai_move, 2,   NULL,
  704.     ai_move, 0,   NULL,
  705.     ai_move, 0,   NULL,
  706.     ai_move, 0,   NULL,
  707.     ai_move, -2,  NULL,
  708.     ai_move, 0,   NULL,
  709.     ai_move, 0,   NULL,
  710.     ai_move, -3,  NULL,
  711.     ai_move, 0,   NULL,
  712.     ai_move, 0,   NULL,
  713.     ai_move, 0,   NULL,
  714.     ai_move, 0,   NULL,
  715.     ai_move, 0,   NULL,
  716.     ai_move, 0,   NULL,
  717.     ai_move, -4,  NULL,
  718.     ai_move, -6,  NULL,
  719.     ai_move, -4,  NULL,
  720.     ai_move, -5,  NULL,
  721.     ai_move, -7,  NULL,
  722.     ai_move, -15, tank_thud,
  723.     ai_move, -5,  NULL,
  724.     ai_move, 0,   NULL,
  725.     ai_move, 0,   NULL,
  726.     ai_move, 0,   NULL
  727. };
  728. mmove_t    tank_move_death = {FRAME_death101, FRAME_death132, tank_frames_death1, tank_dead};
  729.  
  730. void tank_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  731. {
  732.     int        n;
  733.  
  734. // check for gib
  735.     if (self->health <= self->gib_health)
  736.     {
  737.         gi.sound (self, CHAN_VOICE, gi.soundindex ("misc/udeath.wav"), 1, ATTN_NORM, 0);
  738.         for (n= 0; n < 1 /*4*/; n++)
  739.             ThrowGib (self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
  740.         for (n= 0; n < 4; n++)
  741.             ThrowGib (self, "models/objects/gibs/sm_metal/tris.md2", damage, GIB_METALLIC);
  742.         ThrowGib (self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
  743.         ThrowHead (self, "models/objects/gibs/gear/tris.md2", damage, GIB_METALLIC);
  744.         self->deadflag = DEAD_DEAD;
  745.         return;
  746.     }
  747.  
  748.     if (self->deadflag == DEAD_DEAD)
  749.         return;
  750.  
  751. // regular death
  752.     gi.sound (self, CHAN_VOICE, sound_die, 1, ATTN_NORM, 0);
  753.     self->deadflag = DEAD_DEAD;
  754.     self->takedamage = DAMAGE_YES;
  755.  
  756.     self->monsterinfo.currentmove = &tank_move_death;
  757.     
  758. }
  759.  
  760.  
  761. //
  762. // monster_tank
  763. //
  764.  
  765. /*QUAKED monster_tank (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
  766. */
  767. /*QUAKED monster_tank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight
  768. */
  769. void SP_monster_tank (edict_t *self)
  770. {
  771.     if (deathmatch->value)
  772.     {
  773.         G_FreeEdict (self);
  774.         return;
  775.     }
  776.  
  777.     self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2");
  778.     VectorSet (self->mins, -32, -32, -16);
  779.     VectorSet (self->maxs, 32, 32, 72);
  780.     self->movetype = MOVETYPE_STEP;
  781.     self->solid = SOLID_BBOX;
  782.  
  783.     sound_pain = gi.soundindex ("tank/tnkpain2.wav");
  784.     sound_thud = gi.soundindex ("tank/tnkdeth2.wav");
  785.     sound_idle = gi.soundindex ("tank/tnkidle1.wav");
  786.     sound_die = gi.soundindex ("tank/death.wav");
  787.     sound_step = gi.soundindex ("tank/step.wav");
  788.     sound_windup = gi.soundindex ("tank/tnkatck4.wav");
  789.     sound_strike = gi.soundindex ("tank/tnkatck5.wav");
  790.     sound_sight = gi.soundindex ("tank/sight1.wav");
  791.  
  792.     gi.soundindex ("tank/tnkatck1.wav");
  793.     gi.soundindex ("tank/tnkatk2a.wav");
  794.     gi.soundindex ("tank/tnkatk2b.wav");
  795.     gi.soundindex ("tank/tnkatk2c.wav");
  796.     gi.soundindex ("tank/tnkatk2d.wav");
  797.     gi.soundindex ("tank/tnkatk2e.wav");
  798.     gi.soundindex ("tank/tnkatck3.wav");
  799.  
  800.     if (strcmp(self->classname, "monster_tank_commander") == 0)
  801.     {
  802.         self->health = 1000;
  803.         self->gib_health = -225;
  804.     }
  805.     else
  806.     {
  807.         self->health = 750;
  808.         self->gib_health = -200;
  809.     }
  810.  
  811.     self->mass = 500;
  812.  
  813.     self->pain = tank_pain;
  814.     self->die = tank_die;
  815.     self->monsterinfo.stand = tank_stand;
  816.     self->monsterinfo.walk = tank_walk;
  817.     self->monsterinfo.run = tank_run;
  818.     self->monsterinfo.dodge = NULL;
  819.     self->monsterinfo.attack = tank_attack;
  820.     self->monsterinfo.melee = NULL;
  821.     self->monsterinfo.sight = tank_sight;
  822.     self->monsterinfo.idle = tank_idle;
  823.  
  824.     gi.linkentity (self);
  825.     
  826.     self->monsterinfo.currentmove = &tank_move_stand;
  827.     self->monsterinfo.scale = MODEL_SCALE;
  828.  
  829.     walkmonster_start(self);
  830.  
  831.     if (strcmp(self->classname, "monster_tank_commander") == 0)
  832.         self->s.skinnum = 2;
  833. }
  834.