home *** CD-ROM | disk | FTP | other *** search
/ Superpower (Alt) / SUPERPOWER.iso / q / patch / mbq057 / botai.qc < prev    next >
Encoding:
Text File  |  1996-08-31  |  23.7 KB  |  729 lines

  1. /*
  2. ==============================================================================
  3.                             
  4. BOT AI
  5.  
  6. ==============================================================================
  7. */
  8.  
  9. // Prototypes
  10.  
  11. float   ()                                              BotFindTarget;
  12. void    ()                                              bot_ai_stand;
  13. void    (entity attacker, float damage)                 bot_pain;
  14. void    ()                                              bot_die;
  15. void    ()                                              BotSightSound;
  16. void    ()                                              BotFoundTarget;
  17. void    ()                                              BotHuntTarget;
  18. void    (float dist)                                    bot_ai_walk;
  19. void    ()                                              bot_ai_turn;
  20. void    (float dist)                                    bot_ai_run;
  21. void    (void () thinkst)                               BotCheckRefire;
  22. void    ()                                              BotSelfDeActivate;
  23. void    ()                                              bot_fire;
  24. void    ()                                              bot_fire2;
  25. void    ()                                              enforcer_fire;
  26. void    (vector offset)                                 benforcer_fire;
  27. void    (vector org, vector dir)                        launch_spike;
  28. void    ()                                              spike_touch; 
  29. void    ()                                              botrespawn;
  30. // Frame macros
  31.  
  32. $cd /raid/quake/id1/models/enforcer
  33. $origin 0 -6 24
  34. $base base              
  35. $skin skin
  36.  
  37. $frame stand1 stand2 stand3 stand4 stand5 stand6 stand7
  38.  
  39. $frame walk1 walk2 walk3 walk4 walk5 walk6 walk7 walk8 walk9 walk10
  40. $frame walk11 walk12 walk13 walk14 walk15 walk16
  41.  
  42. $frame run1 run2 run3 run4 run5 run6 run7 run8
  43.  
  44. $frame attack1 attack2 attack3 attack4 attack5 attack6
  45. $frame attack7 attack8 attack9 attack10
  46.  
  47. $frame death1 death2 death3 death4 death5 death6 death7 death8
  48. $frame death9 death10 death11 death12 death13 death14
  49.  
  50. $frame fdeath1 fdeath2 fdeath3 fdeath4 fdeath5 fdeath6 fdeath7 fdeath8
  51. $frame fdeath9 fdeath10 fdeath11
  52.  
  53. $frame paina1 paina2 paina3 paina4
  54.  
  55. $frame painb1 painb2 painb3 painb4 painb5
  56.  
  57. $frame painc1 painc2 painc3 painc4 painc5 painc6 painc7 painc8
  58.  
  59. $frame paind1 paind2 paind3 paind4 paind5 paind6 paind7 paind8
  60. $frame paind9 paind10 paind11 paind12 paind13 paind14 paind15 paind16
  61. $frame paind17 paind18 paind19
  62.  
  63. void()  bot_stand1      =[      $stand1,        bot_stand2      ] {bot_ai_stand();};
  64. void()  bot_stand2      =[      $stand2,        bot_stand3      ] {bot_ai_stand();};
  65. void()  bot_stand3      =[      $stand3,        bot_stand4      ] {bot_ai_stand();};
  66. void()  bot_stand4      =[      $stand4,        bot_stand5      ] {bot_ai_stand();};
  67. void()  bot_stand5      =[      $stand5,        bot_stand6      ] {bot_ai_stand();};
  68. void()  bot_stand6      =[      $stand6,        bot_stand7      ] {bot_ai_stand();};
  69. void()  bot_stand7      =[      $stand7,        bot_stand1      ] {bot_ai_stand();};
  70.  
  71. void()  bot_walk1       =[      $walk1 ,        bot_walk2       ]
  72. {
  73.     if (random() < 0.2)
  74.         sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE);
  75.     bot_ai_walk(4);
  76. };
  77. void()  bot_walk2       =[      $walk2 ,        bot_walk3       ] {bot_ai_walk(8);};
  78. void()  bot_walk3       =[      $walk3 ,        bot_walk4       ] {bot_ai_walk(8);};
  79. void()  bot_walk4       =[      $walk4 ,        bot_walk5       ] {bot_ai_walk(6);};
  80. void()  bot_walk5       =[      $walk5 ,        bot_walk6       ] {bot_ai_walk(8);};
  81. void()  bot_walk6       =[      $walk6 ,        bot_walk7       ] {bot_ai_walk(4);};
  82. void()  bot_walk7       =[      $walk7 ,        bot_walk8       ] {bot_ai_walk(4);};
  83. void()  bot_walk8       =[      $walk8 ,        bot_walk9       ] {bot_ai_walk(2);};
  84. void()  bot_walk9       =[      $walk9 ,        bot_walk10      ] {bot_ai_walk(4);};
  85. void()  bot_walk10      =[      $walk10,        bot_walk11      ] {bot_ai_walk(6);};
  86. void()  bot_walk11      =[      $walk11,        bot_walk12      ] {bot_ai_walk(8);};
  87. void()  bot_walk12      =[      $walk12,        bot_walk13      ] {bot_ai_walk(2);};
  88. void()  bot_walk13      =[      $walk13,        bot_walk14      ] {bot_ai_walk(4);};
  89. void()  bot_walk14      =[      $walk14,        bot_walk15      ] {bot_ai_walk(2);};
  90. void()  bot_walk15      =[      $walk15,        bot_walk16      ] {bot_ai_walk(8);};
  91. void()  bot_walk16      =[      $walk16,        bot_walk1       ] {bot_ai_walk(4);};
  92.  
  93. void()  bot_run1        =[      $run1  ,        bot_run2        ]
  94. {
  95.     if (random() < 0.2)
  96.         sound (self, CHAN_VOICE, "enforcer/idle1.wav", 1, ATTN_IDLE);
  97.     bot_ai_run(18);
  98. };
  99. void()  bot_run2        =[      $run2  ,        bot_run3        ] {bot_ai_run(14);};
  100. void()  bot_run3        =[      $run3  ,        bot_run4        ] {bot_ai_run(7);};
  101. void()  bot_run4        =[      $run4  ,        bot_run5        ] {bot_ai_run(12);};
  102. void()  bot_run5        =[      $run5  ,        bot_run6        ] {bot_ai_run(14);};
  103. void()  bot_run6        =[      $run6  ,        bot_run7        ] {bot_ai_run(14);};
  104. void()  bot_run7        =[      $run7  ,        bot_run8        ] {bot_ai_run(7);};
  105. void()  bot_run8        =[      $run8  ,        bot_run1        ] {bot_ai_run(11);};
  106.  
  107. void()  bot_atk1        =[      $attack1,       bot_atk2        ] {ai_face();};
  108. void()  bot_atk2        =[      $attack2,       bot_atk3        ] {ai_face();};
  109. void()  bot_atk3        =[      $attack3,       bot_atk4        ] {ai_face();};
  110. void()  bot_atk4        =[      $attack4,       bot_atk5        ] {ai_face();};
  111. void()  bot_atk5        =[      $attack5,       bot_atk6        ] {ai_face();};
  112. void()  bot_atk6        =[      $attack6,       bot_atk7        ] {bot_attack();};
  113. void()  bot_atk7        =[      $attack6,       bot_atk8        ] {ai_face();};
  114. void()  bot_atk8        =[      $attack5,       bot_atk9        ] {ai_face();};
  115. void()  bot_atk9        =[      $attack6,       bot_atk10       ] {ai_face();};
  116. void()  bot_atk10       =[      $attack5,       bot_atk11       ] {bot_attack();};
  117. void()  bot_atk11       =[      $attack6,       bot_atk12       ] {ai_face();};
  118. void()  bot_atk12       =[      $attack5,       bot_atk13       ] {ai_face();};
  119. void()  bot_atk13       =[      $attack6,       bot_atk14       ] {ai_face();};
  120. void()  bot_atk14       =[      $attack5,       bot_atk15       ] {ai_face();};
  121. void()  bot_atk15       =[      $attack6,       bot_atk16       ] {bot_attack();};
  122. void()  bot_atk16       =[      $attack5,       bot_atk17       ] {ai_face();};
  123. void()  bot_atk17       =[      $attack6,       bot_atk18       ] {ai_face();};
  124. void()  bot_atk18       =[      $attack7,       bot_atk19       ] {ai_face();};
  125. void()  bot_atk19       =[      $attack8,       bot_atk20       ] {ai_face();};
  126. void()  bot_atk20       =[      $attack9,       bot_atk21       ] {ai_face();};
  127. void()  bot_atk21       =[      $attack10,      bot_run1        ]
  128.  
  129. {
  130.     ai_face();
  131.     BotCheckRefire (bot_atk1);
  132. };
  133.  
  134. void()  bot_paina1      =[      $paina1,        bot_paina2      ] {};
  135. void()  bot_paina2      =[      $paina2,        bot_paina3      ] {};
  136. void()  bot_paina3      =[      $paina3,        bot_paina4      ] {};
  137. void()  bot_paina4      =[      $paina4,        bot_run1        ] {};
  138.  
  139. void()  bot_painb1      =[      $painb1,        bot_painb2      ] {};
  140. void()  bot_painb2      =[      $painb2,        bot_painb3      ] {};
  141. void()  bot_painb3      =[      $painb3,        bot_painb4      ] {};
  142. void()  bot_painb4      =[      $painb4,        bot_painb5      ] {};
  143. void()  bot_painb5      =[      $painb5,        bot_run1        ] {};
  144.  
  145. void()  bot_painc1      =[      $painc1,        bot_painc2      ] {};
  146. void()  bot_painc2      =[      $painc2,        bot_painc3      ] {};
  147. void()  bot_painc3      =[      $painc3,        bot_painc4      ] {};
  148. void()  bot_painc4      =[      $painc4,        bot_painc5      ] {};
  149. void()  bot_painc5      =[      $painc5,        bot_painc6      ] {};
  150. void()  bot_painc6      =[      $painc6,        bot_painc7      ] {};
  151. void()  bot_painc7      =[      $painc7,        bot_painc8      ] {};
  152. void()  bot_painc8      =[      $painc8,        bot_run1        ] {};
  153.  
  154. void()  bot_paind1      =[      $paind1,        bot_paind2      ] {};
  155. void()  bot_paind2      =[      $paind2,        bot_paind3      ] {};
  156. void()  bot_paind3      =[      $paind3,        bot_paind4      ] {};
  157. void()  bot_paind4      =[      $paind4,        bot_paind5      ] {ai_painforward(2);};
  158. void()  bot_paind5      =[      $paind5,        bot_paind6      ] {ai_painforward(1);};
  159. void()  bot_paind6      =[      $paind6,        bot_paind7      ] {};
  160. void()  bot_paind7      =[      $paind7,        bot_paind8      ] {};
  161. void()  bot_paind8      =[      $paind8,        bot_paind9      ] {};
  162. void()  bot_paind9      =[      $paind9,        bot_paind10     ] {};
  163. void()  bot_paind10     =[      $paind10,       bot_paind11     ] {};
  164. void()  bot_paind11     =[      $paind11,       bot_paind12     ] {ai_painforward(1);};
  165. void()  bot_paind12     =[      $paind12,       bot_paind13     ] {ai_painforward(1);};
  166. void()  bot_paind13     =[      $paind13,       bot_paind14     ] {ai_painforward(1);};
  167. void()  bot_paind14     =[      $paind14,       bot_paind15     ] {};
  168. void()  bot_paind15     =[      $paind15,       bot_paind16     ] {};
  169. void()  bot_paind16     =[      $paind16,       bot_paind17     ] {ai_pain(1);};
  170. void()  bot_paind17     =[      $paind17,       bot_paind18     ] {ai_pain(1);};
  171. void()  bot_paind18     =[      $paind18,       bot_paind19     ] {};
  172. void()  bot_paind19     =[      $paind19,       bot_run1        ] {};
  173.  
  174. void()  bot_die1        =[      $death1,        bot_die2        ] {};
  175. void()  bot_die2        =[      $death2,        bot_die3        ] {};
  176. void()  bot_die3        =[      $death3,        bot_die4        ]
  177. {
  178.     self.solid = SOLID_NOT;
  179.     self.ammo_cells = 5;
  180.     if (random () < 0.25) DropBackpack();
  181. };
  182. void()  bot_die4        =[      $death4,        bot_die5        ] {ai_forward(14);};
  183. void()  bot_die5        =[      $death5,        bot_die6        ] {ai_forward(2);};
  184. void()  bot_die6        =[      $death6,        bot_die7        ] {};
  185. void()  bot_die7        =[      $death7,        bot_die8        ] {};
  186. void()  bot_die8        =[      $death8,        bot_die9        ] {};
  187. void()  bot_die9        =[      $death9,        bot_die10       ] {ai_forward(3);};
  188. void()  bot_die10       =[      $death10,       bot_die11       ] {ai_forward(5);};
  189. void()  bot_die11       =[      $death11,       bot_die12       ] {ai_forward(5);};
  190. void()  bot_die12       =[      $death12,       bot_die13       ] {ai_forward(5);};
  191. void()  bot_die13       =[      $death13,       bot_die14       ] {};
  192. void()  bot_die14       =[      $death14,       bot_die14       ] {BotSelfDeActivate();};
  193.  
  194. void()  bot_fdie1       =[      $fdeath1,       bot_fdie2       ] {};
  195. void()  bot_fdie2       =[      $fdeath2,       bot_fdie3       ] {};
  196. void()  bot_fdie3       =[      $fdeath3,       bot_fdie4       ] 
  197. {
  198.     self.solid = SOLID_NOT;
  199.     self.ammo_cells = 5;
  200.       
  201. };
  202. void()  bot_fdie4       =[      $fdeath4,       bot_fdie5       ] {};
  203. void()  bot_fdie5       =[      $fdeath5,       bot_fdie6       ] {};
  204. void()  bot_fdie6       =[      $fdeath6,       bot_fdie7       ] {};
  205. void()  bot_fdie7       =[      $fdeath7,       bot_fdie8       ] {};
  206. void()  bot_fdie8       =[      $fdeath8,       bot_fdie9       ] {};
  207. void()  bot_fdie9       =[      $fdeath9,       bot_fdie10      ] {};
  208. void()  bot_fdie10      =[      $fdeath10,      bot_fdie11      ] {};
  209. void()  bot_fdie11      =[      $fdeath11,      bot_fdie11      ] {BotSelfDeActivate();};
  210.  
  211.  
  212. float() BotFindTarget =
  213. {
  214.     local entity head, selected;
  215.     local float dist;
  216.     dist = 1500;    // awareness radius of bot, increasing it slows down game
  217.     selected = world;
  218.  
  219.     head = findradius(self.origin, 1500);
  220.     while(head)
  221.     {
  222.         if((!(head.flags & FL_NOTARGET) && 
  223.             (!(head.items & IT_INVISIBILITY)))  //* BGADMbot - duh 
  224.             &&
  225.             ((head.flags & FL_CLIENT) 
  226.             || (head.flags & FL_MONSTER) 
  227.             || (head.classname == "bot")))
  228.         if (((teamplay) &&  (head.team != self.owner.team)) || (!teamplay))
  229.         if ((head.health > 1) && (head != self))
  230.         if (visible(head))
  231.         if (trace_plane_dist < dist)
  232.         if ((head.health > 0) && (head !=self))
  233.            {
  234.             selected = head;
  235.             dist = trace_plane_dist;
  236.            }
  237.         head = head.chain;
  238.     }
  239.     self.enemy = selected;
  240.         
  241.     if (self.enemy == world)
  242.         return FALSE;
  243.     else
  244.     {
  245.         self.oldenemy=self.enemy; //* BGADMbot - in case bot decides to
  246.                       //  attack someone else, oldenemy
  247.                       //  can always be re-set as enemy
  248.         BotFoundTarget();
  249.         return TRUE;
  250.     }
  251. };
  252.  
  253. //=============================================================
  254. // bot_ai_stand - bot stands in place until target acquired,
  255. // and starts to walk if pausetime has expired
  256. //=============================================================
  257. void() bot_ai_stand =
  258. {
  259.     
  260.     if (BotFindTarget ())
  261.         return;
  262.     
  263.     if (time > self.pausetime)
  264.     {
  265.         self.th_walk ();
  266.         return;
  267.     }
  268. };
  269.  
  270.  
  271. //=============================================================
  272. // bot_pain
  273. //=============================================================
  274. void(entity attacker, float damage)     bot_pain =
  275. {
  276.     local float r;
  277.     local entity oldself;
  278.     local entity spot;
  279.     if (random () < 0.2) self.enemy=attacker; // BGADMbot - 20% chance
  280.                           // bot may make attacker
  281.                           // his enemy
  282.     r = random ();
  283.     if (self.pain_finished > time)
  284.         return;
  285.  
  286.     
  287.     if (r < 0.5)
  288.         sound (self, CHAN_VOICE, "enforcer/pain1.wav", 1, ATTN_NORM);
  289.     else
  290.         sound (self, CHAN_VOICE, "enforcer/pain2.wav", 1, ATTN_NORM);
  291.  
  292.  
  293.     if (r < 0.2)
  294.     {
  295.         self.pain_finished = time + 1;
  296.         bot_paina1 ();
  297.     }
  298.     else if (r < 0.4)
  299.     {
  300.         self.pain_finished = time + 1;
  301.         bot_painb1 ();
  302.     }
  303.     else if (r < 0.7)
  304.     {
  305.         self.pain_finished = time + 1;
  306.         bot_painc1 ();
  307.     }
  308.     else
  309.     {
  310.         self.pain_finished = time + 2;
  311.         bot_paind1 ();
  312.     }
  313.     
  314. };
  315.  
  316. //=============================================================
  317. // bot_die
  318. //=============================================================
  319. void() bot_die =
  320. {
  321.     sound (self, CHAN_VOICE, "enforcer/death1.wav", 1, ATTN_NORM);
  322.     if (random() > 0.5)
  323.         bot_die1 ();
  324.     else
  325.         bot_fdie1 ();
  326.  
  327. // death frame sequence includes bot deactivation       
  328. };
  329.  
  330.  
  331. //=============================================================
  332. // BotSightSound
  333. //=============================================================
  334. void() BotSightSound =
  335. {
  336.     local float     rsnd;
  337.  
  338.     while (random() < 0.3)   //BGADMbot - added for anti-annoyance sake
  339.     {
  340.     rsnd = rint(random() * 3);                      
  341.     if (rsnd == 1)
  342.         sound (self, CHAN_VOICE, "enforcer/sight1.wav", 1, ATTN_NORM);
  343.     else if (rsnd == 2)
  344.         sound (self, CHAN_VOICE, "enforcer/sight2.wav", 1, ATTN_NORM);
  345.     else if (rsnd == 0)
  346.         sound (self, CHAN_VOICE, "enforcer/sight3.wav", 1, ATTN_NORM);
  347.     else
  348.         sound (self, CHAN_VOICE, "enforcer/sight4.wav", 1, ATTN_NORM);
  349.     }
  350. };
  351.  
  352.  
  353. //=============================================================
  354. // BotHuntTarget
  355. //=============================================================
  356. void() BotHuntTarget =
  357. {
  358.     self.goalentity = self.enemy;
  359.     self.think = self.th_run;
  360.     self.ideal_yaw = vectoyaw(self.enemy.origin - self.origin);
  361.     self.nextthink = time + 0.1;
  362.     SUB_AttackFinished (0.1);       // wait a while before first attack
  363. };
  364.  
  365.  
  366. //=============================================================
  367. // BotFoundTarget
  368. //=============================================================
  369. void() BotFoundTarget =
  370. {
  371.     local float f_dist;
  372.     local string s_dist;
  373.     f_dist = vlen (self.enemy.origin - self.origin);
  374.     s_dist = ftos (f_dist);
  375.  
  376.     self.show_hostile = time + 1;           // wake up other monsters
  377.     
  378.     BotSightSound ();
  379.     BotHuntTarget ();
  380. };
  381.  
  382.  
  383. //=============================================================
  384. // bot_ai_walk - bot is walking, looking for enemies
  385. //=============================================================
  386. void(float dist) bot_ai_walk =
  387. {
  388.     if (BotFindTarget ())
  389.         return;
  390.  
  391.     movetogoal (dist);
  392. };
  393.  
  394. //=============================================================
  395. // bot_ai_turn - turn towards ideal_yaw if no enemy sighted
  396. //=============================================================
  397. void() bot_ai_turn =
  398. {
  399.     if (BotFindTarget ())
  400.         return;
  401.     
  402.     ChangeYaw ();
  403. };
  404.  
  405.  
  406. //=============================================================
  407. // bot_ai_run - still needs a little work
  408. //=============================================================
  409. void(float dist) bot_ai_run =
  410. {
  411.     local   vector  delta;
  412.     local   float   axis;
  413.     local   float   direct, ang_rint, ang_floor, ang_ceil;
  414.     
  415.     movedist = dist;
  416.  
  417.     if (self.enemy.health <= 0)
  418.     {
  419.         self.enemy = world;
  420.         if (self.oldenemy.health > 0)     //  BGADMbot - this isnt new, but
  421.         {                                   // I added it on BotCheckRefire 
  422.             self.enemy = self.oldenemy; // as well
  423.             BotHuntTarget ();           //  
  424.         }
  425.         else
  426.         {
  427.             if (BotFindTarget())
  428.                 return;
  429.             else
  430.             {
  431.                 self.th_walk ();
  432.                 return;
  433.             }
  434.         }
  435.     }
  436.  
  437.     self.show_hostile = time + 1;           // wake up other monsters
  438.  
  439.     enemy_vis = visible(self.enemy);
  440.     if (enemy_vis)
  441.         self.search_time = time + 5;
  442.  
  443.     enemy_infront = infront(self.enemy);
  444.     enemy_range = range(self.enemy);
  445.     enemy_yaw = vectoyaw(self.enemy.origin - self.origin);
  446.     
  447.     if (self.attack_state == AS_MISSILE)
  448.     {
  449.         ai_run_missile ();
  450.         return;
  451.     }
  452.     if (self.attack_state == AS_MELEE)
  453.     {
  454.         ai_run_melee ();
  455.         return;
  456.     }
  457.  
  458.     if (CheckAnyAttack ())
  459.         return;                                 // beginning an attack
  460.         
  461.     if (self.attack_state == AS_SLIDING)
  462.     {
  463.         ai_run_slide ();
  464.         return;
  465.     }
  466.         
  467.     movetogoal (dist);              // done in C code...
  468. };
  469.  
  470.  
  471. //=============================================================
  472. // BotCheckRefire
  473. //=============================================================
  474. void (void () thinkst) BotCheckRefire =
  475. {
  476.     
  477.     if (!visible (self.enemy) || (self.enemy.health <= 0))        
  478.         {
  479.         if (self.enemy.health <= 0) {
  480.         self.frags=self.frags + 1;    // BGADMbot - counts frags for bots
  481.         self.enemy.frags=self.enemy.frags - 1;    // counts frags for bots
  482.         if (self.oldenemy.health>0) //if oldenemy still kickin
  483.         self.enemy=self.oldenemy;  //change to old enemy  
  484.         HuntTarget();         //Hunt him down
  485.         }
  486.         return;
  487.         } 
  488.         self.think = thinkst;
  489. };
  490.  
  491.  
  492. //=============================================================
  493. // BotSelfDeActivate - Bot deactivates itself
  494. //=============================================================
  495. void () BotSelfDeActivate =
  496. {
  497.     
  498.     CopyToBodyQue(self); // BGADMbot - now leaves a body, 
  499.     
  500.     botrespawn();        // then respawns(bot.qc)
  501. };
  502.  
  503. void() bot_FireShotgun =
  504. {
  505.     local vector dir;
  506.  
  507.     self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  508.     dir = aim (self, 100000);
  509.     FireBullets (6, dir, '0.04 0.04 0');
  510. };
  511.  
  512. void() bot_FireSuperShotgun =
  513. {
  514.     local vector dir;
  515.  
  516.     if (self.currentammo == 1)
  517.     {
  518.         bot_FireShotgun ();
  519.         return;
  520.     }
  521.         
  522.     self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  523.     dir = aim (self, 100000);
  524.     FireBullets (14, dir, '0.14 0.08 0');
  525. };
  526.  
  527. void() bot_FireRocket =
  528. {
  529.     local   entity missile, mpuff;
  530.     
  531.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  532.     
  533.     missile = spawn ();
  534.     missile.owner = self;
  535.     missile.movetype = MOVETYPE_FLYMISSILE;
  536.     missile.solid = SOLID_BBOX;
  537.     makevectors (self.angles);
  538.     missile.velocity = aim(self, 1000);
  539.     missile.velocity = missile.velocity * 1000;
  540.     missile.angles = vectoangles(missile.velocity);
  541.     missile.touch = T_MissileTouch;
  542.     missile.nextthink = time + 5;
  543.     missile.think = SUB_Remove;
  544.     setmodel (missile, "progs/missile.mdl");
  545.     setsize (missile, '0 0 0', '0 0 0');            
  546.     setorigin (missile, self.origin + '0 0 16');
  547. };
  548.  
  549. void () bot_fire =
  550. {
  551.     local vector org;
  552.     local vector dir;
  553.     local float ox;
  554.     
  555.     ox = 4;
  556.  
  557.     self.effects = self.effects | EF_MUZZLEFLASH;
  558.     makevectors (self.angles);
  559.     sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  560.     self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  561.     org = self.origin + v_forward * 30 + v_right*ox + '0 0 16';
  562.     dir = self.enemy.origin - self.origin;
  563.     dir = normalize(dir);
  564.     launch_spike(org, dir);
  565. };
  566.  
  567. void () bot_fire2 =
  568. {
  569.     local vector    dir;
  570.     local vector    org;
  571.     
  572.     self.oldenemy = self.enemy;
  573.    
  574.     if (!visible (self.enemy) || (self.enemy.health <= 0))
  575.     {
  576.         if (BotFindTarget ())
  577.             return;
  578.     
  579.         ChangeYaw ();
  580.         self.enemy = self.oldenemy;
  581.     }
  582.  
  583.     makevectors (self.angles);
  584.     sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  585.     self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  586.     org = self.origin + '0 0 16';
  587.     dir = self.enemy.origin - self.origin;
  588.     dir = normalize(dir);
  589.     launch_spike (org, dir);
  590.     newmis.touch = superspike_touch;
  591.     setmodel (newmis, "progs/s_spike.mdl");
  592.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);               
  593. };
  594.  
  595. void(vector offset) benforcer_fire =
  596. {
  597.     local vector org;
  598.     local vector dir;
  599.     local float ox;
  600.     
  601.     ox = 4;
  602.  
  603.     self.effects = self.effects | EF_MUZZLEFLASH;
  604.     makevectors (self.angles);
  605.     sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  606.     
  607.     org = self.origin + v_forward * 30 + v_right*ox + '0 0 16';
  608.     dir = self.enemy.origin - self.origin;
  609.     dir = normalize(dir);
  610.     launch_spike(org, dir);
  611.     org = org + offset;
  612.     launch_spike(org, dir);
  613. };
  614.  
  615. void() bot_SetCurrentAmmo =
  616. {
  617.     self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  618.     
  619.     if (self.weapon == IT_SHOTGUN)
  620.     {
  621.         self.currentammo = self.ammo_shells;
  622.         self.items = self.items | IT_SHELLS;
  623.     }
  624.     else if (self.weapon == IT_SUPER_SHOTGUN)
  625.     {
  626.         self.currentammo = self.ammo_shells;
  627.         self.items = self.items | IT_SHELLS;
  628.     }
  629.     else if (self.weapon == IT_NAILGUN)
  630.     {
  631.         self.currentammo = self.ammo_nails;
  632.         self.items = self.items | IT_NAILS;
  633.     }
  634.     else if (self.weapon == IT_SUPER_NAILGUN)
  635.     {
  636.         self.currentammo = self.ammo_nails;
  637.         self.items = self.items | IT_NAILS;
  638.     }
  639.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  640.     {
  641.         self.currentammo = self.ammo_rockets;
  642.         self.items = self.items | IT_ROCKETS;
  643.     }
  644.     else
  645.     {
  646.         self.currentammo = 0;
  647.         self.weaponmodel = "";
  648.         self.weaponframe = 0;
  649.     }
  650. };
  651. /*
  652. ====================================================
  653. bot_bestweapon - AI to choose which weapon is best
  654. ====================================================
  655. */
  656. float () bot_bestweapon =
  657. {
  658.     local   float   it;
  659.     
  660.     it = self.items;
  661.  
  662.     if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
  663.         return IT_ROCKET_LAUNCHER;
  664.     else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  665.         return IT_SUPER_NAILGUN;
  666.     else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  667.         return IT_SUPER_SHOTGUN;
  668.     else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  669.         return IT_NAILGUN;
  670.  
  671.     return IT_SHOTGUN;
  672.  
  673. };
  674. /*
  675. ===============================================
  676. bot_CheckNoAmmo - checks to see if he has ammo 
  677. ===============================================
  678. */
  679. float() bot_CheckNoAmmo =
  680. {
  681.     if (self.currentammo > 0)
  682.         return TRUE;
  683.  
  684.     self.weapon = bot_bestweapon ();
  685.  
  686.     bot_SetCurrentAmmo ();
  687.     
  688.     return FALSE;
  689. };
  690. /*
  691. ==========================
  692. bot_attack - fires weapon
  693. ==========================
  694. */
  695. void() bot_attack =
  696. {
  697.     local   float   r;
  698.  
  699.     if (!visible (self.enemy) || (self.enemy.health <= 0))
  700.         return;
  701.  
  702.     if (!bot_CheckNoAmmo ())
  703.         return;
  704.  
  705.     makevectors     (self.angles);     
  706.     self.show_hostile = time + 1;   // wake monsters up
  707.  
  708.     if (self.weapon == IT_SHOTGUN)
  709.     {
  710.         bot_FireShotgun ();
  711.     }
  712.     else if (self.weapon == IT_SUPER_SHOTGUN)
  713.     {
  714.         bot_FireSuperShotgun ();
  715.     }
  716.     else if (self.weapon == IT_NAILGUN)
  717.     {
  718.         bot_fire ();
  719.     }
  720.     else if (self.weapon == IT_SUPER_NAILGUN)
  721.     {
  722.         bot_fire2 ();
  723.     }
  724.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  725.     {
  726.         bot_FireRocket();
  727.     }
  728. };
  729.