]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/bot/bot_fight.qc
commit 1.2.1 game media
[divverent/nexuiz.git] / data / qcsrc / bot / bot_fight.qc
1 /***********************************************
2 *                                              *
3 *             FrikBot Fight Code               *
4 *      "Because I ain't no Ghandi code"        *
5 *                                              *
6 ***********************************************/
7
8 /*
9
10 This program is in the Public Domain. My crack legal
11 team would like to add:
12
13 RYAN "FRIKAC" SMITH IS PROVIDING THIS SOFTWARE "AS IS"
14 AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE
15 ACCURACY, CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR
16 FUNCTIONING OF THIS SOFTWARE AND/OR DOCUMENTATION. IN
17 NO EVENT WILL RYAN "FRIKAC" SMITH BE LIABLE FOR ANY
18 GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL,
19 EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF RYAN "FRIKAC"
20 SMITH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
21 DAMAGES, IRRESPECTIVE OF THE CAUSE OF SUCH DAMAGES. 
22
23 You accept this software on the condition that you
24 indemnify and hold harmless Ryan "FrikaC" Smith from
25 any and all liability or damages to third parties,
26 including attorney fees, court costs, and other
27 related costs and expenses, arising out of your use
28 of this software irrespective of the cause of said
29 liability. 
30
31 The export from the United States or the subsequent
32 reexport of this software is subject to compliance
33 with United States export control and munitions
34 control restrictions. You agree that in the event you
35 seek to export this software, you assume full
36 responsibility for obtaining all necessary export
37 licenses and approvals and for assuring compliance
38 with applicable reexport restrictions. 
39
40 Any reproduction of this software must contain
41 this notice in its entirety. 
42
43 */
44
45 .entity avoid;
46
47 float(entity e) bot_size_player =
48 {
49         local float sz;
50
51         sz = e.health + e.armorvalue * e.armortype;
52         if (e.weapon == 32)
53                 sz = sz + 60;
54         else if (e.weapon == 64)
55                 sz = sz + 60;
56         else if (e.weapon == 16)
57                 sz = sz + 50;
58         else if (e.weapon == 8)
59                 sz = sz + 50;
60         else if (e.weapon == 4)
61                 sz = sz + 40;
62         else if (e.weapon == 2)
63                 sz = sz + 40;
64         else if (e.weapon == 1)
65                 sz = sz + 10;
66         else if (e.weapon == 4096)
67                 sz = sz - 50;
68         if (e.items & 4194304) // Quad
69                 sz = sz + 200;
70         if (e.items & 1048576) // Invul
71                 sz = sz + 300;
72         if (e.items & 524288) // Invis
73                 sz = sz + 250;
74         return sz;
75 };
76
77 void() bot_dodge_stuff =
78 {
79         local entity foe;
80         local float foedist, avdist, /*scandist, */foesz, flen, tsz;
81         local vector v;
82
83         if (waypoint_mode > WM_LOADED)
84                 return;
85
86         self.avoid = world;
87
88
89         if (self.enemy)
90         {
91                 v = self.origin - realorigin(self.enemy);
92                 foedist = vlen(v);
93                 foesz = bot_size_player(self.enemy);
94         }
95         else 
96         {
97                 foedist = 3000;
98                 foesz = 9999999;
99         }
100         avdist = 256;
101
102         foe = find(world, classname, "grenade");
103         while(foe)
104         {
105                 flen = vlen(foe.origin - self.origin);
106                 if (flen < avdist)
107                 {
108                         avdist = flen;
109                         self.avoid = foe;
110                 }
111                 foe = find(foe, classname, "grenade");
112         }
113         if (!self.avoid)
114         {
115                 foe = find(world, classname, "missile");
116                 while(foe)
117                 {
118                         if (foe.owner != self)
119                         {
120                                 flen = vlen(foe.origin - self.origin);
121                                 if (flen < avdist)
122                                 {
123                                         avdist = flen;
124                                         self.avoid = foe;
125                                 }
126                         }
127                         foe = find(foe, classname, "missile");
128                 }
129                 if (!self.avoid)
130                 {
131                         foe = find(world, classname, "spike");
132                         while(foe)
133                         {
134                                 if (foe.owner != self)
135                                 {
136                                         flen = vlen(foe.origin - self.origin);
137                                         if (flen < avdist)
138                                         {
139                                                 avdist = flen;
140                                                 self.avoid = foe;
141                                         }
142                                 }
143                                 foe = find(foe, classname, "spike");
144                         }
145                 }
146         }
147         if (coop)
148         {
149                 if (!self.enemy)
150                 {
151                         foe = findradius(self.origin, foedist);
152                         while(foe)
153                         {
154                                 if(foe.flags & FL_MONSTER)
155                                 {
156                                         if(foe.health > 0)
157                                         {
158                                                 flen = vlen(foe.origin - self.origin);
159                                                 if (flen < foedist)
160                                                 {
161                                                         tsz = bot_size_player(foe);
162                                                         if (tsz < foesz)
163                                                         {
164                                                                 if (fisible(foe))
165                                                                 {
166                                                                         self.enemy = foe;
167                                                                         foedist = flen;
168                                                                         foesz = tsz;
169                                                                 }
170                                                         }
171                                                 }
172                                         }
173                                 }
174                                 foe = foe.chain;
175                         }
176                 }               
177         }
178         else
179         {
180                 foe = player_head;
181                 while(foe)
182                 {
183                         if(foe != self)
184                         {
185                                 if (foe.modelindex != 0)
186                                 {
187                                         if (foe.health > 0)
188                                         {
189                                                 if (!(teamplay && self.team == foe.team))
190                                                 {
191                                                         flen = vlen(foe.origin - self.origin);
192                                                         if (flen < foedist)
193                                                         {
194                                                                 tsz = bot_size_player(foe);
195                                                                 if (tsz < foesz)
196                                                                 {
197                                                                         if (fov(foe) || foe.b_sound > time || self.b_skill == 3)
198                                                                         {
199                                                                                 if (fisible(foe))
200                                                                                 {
201                                                                                         self.enemy = foe;
202                                                                                         foedist = vlen(foe.origin - self.origin);
203                                                                                 }
204                                                                         }
205                                                                 }
206                                                         }
207                                                 }
208                                         }
209                                 }
210                         }
211                         foe = foe._next;
212                 }
213         }
214 };
215
216
217
218
219 /*
220 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
221
222 weapon_range
223
224 _x "sweet spot range" - try to maintain this range if possible
225 _y minimum range bot can be to be effective (rl/gl) (move away)
226 _z maximum range bot can be to be effective (lg/axe) (move in)
227 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
228 */
229
230 vector(float wep) weapon_range =
231 {
232         if (wep == 4096) // IT_AXE
233                 return '48 0 64';
234         else if (wep == 1) // IT_SHOTGUN
235                 return '128 0 99999';
236         else if (wep == 2) // IT_SUPER_SHOTGUN
237                 return '128 0 99999';
238         else if (wep == 4) // IT_NAILGUN
239                 return '180 0 3000';
240         else if (wep == 8) // IT_SUPER_NAILGUN
241                 return '180 0 3000';
242         else if (wep == 16) // IT_GRENADE_LAUNCHER
243                 return '180 48 3000';
244         else if (wep == 32) // IT_ROCKET_LAUNCHER
245                 return '180 48 3000';
246         else if (wep == 64) // IT_LIGHTNING
247                 return '350 0 512';
248 };
249 /*
250 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
251
252 bot_weapon_switch
253
254 Pick a weapon based on range / ammo
255
256 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
257 */
258
259 void(float brange) bot_weapon_switch =
260 {
261         local   float   it, flag, pulse;
262         local vector v;
263
264         it = self.items & 127;
265
266         while(it)
267         {
268                 if ((self.ammo_rockets >= 1) && (it & 32))
269                 {
270                         flag = 32;
271                         pulse = 7;
272                 }
273                 else if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & 64))
274                 {
275                         flag = 64;
276                         pulse = 8;
277                 }
278                 else if(self.ammo_nails >= 2 && (it & 8))
279                 {
280                         flag = 8;
281                         pulse = 5;
282                 }
283                 else if ((self.ammo_rockets >= 1) && (it & 16))
284                 {
285                         flag = 16;
286                         pulse = 6;
287                 }
288                 else if(self.ammo_shells >= 2 && (it & 2))
289                 {
290                         flag = 2;
291                         pulse = 3;
292                 }
293                 else if(self.ammo_nails >= 1 && (it & 4))
294                 {
295                         flag = 4;
296                         pulse = 4;
297                 }
298                 else if(self.ammo_shells >= 1 && (it & 1))
299                 {
300                         flag = 1;
301                         pulse = 2;
302                 }
303                 else
304                 {
305                         if (pulse)
306                                 self.impulse = pulse;
307                         return;
308                 }
309
310                 if (brange == -1)
311                 {
312                         if (pulse)
313                                 self.impulse = pulse;
314                         return;
315                 }
316
317                 v = weapon_range(flag);
318                 if (brange < v_y || brange > v_z)
319                         it = it - flag;
320                 else
321                 {
322                         if (pulse)
323                                 self.impulse = pulse;
324                         return;
325                 }
326         }
327 };
328
329 void() bot_shoot = 
330 {
331         // quick little function to stop making him shoot the wrong way ! Argh
332         local float g;
333         g = angcomp(self.v_angle_x, self.b_angle_x);
334         if (fabs(g) > 30)
335                 return; // argh, too far away
336         g = angcomp(self.v_angle_y, self.b_angle_y);
337         if (fabs(g) > 30)
338                 return; // not again!
339         self.button0 = TRUE;
340 };
341
342 /*
343 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
344
345 Bot_fight_style
346
347 This is the core of the bot's thinking when
348 attacking an enemy. 
349
350 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
351 */
352
353 void() bot_fight_style =
354 {
355         local vector v, v1, v2, org;
356         local float foedist, mysz, foesz;
357
358
359         if (self.enemy.health <= 0)
360         {
361                 self.enemy = world;
362                 return;
363         }
364         else if (!self.enemy.takedamage)
365         {
366                 self.enemy = world;
367                 return;
368         }
369         else if (!fisible(self.enemy))
370         {
371                 self.enemy = world;
372                 return;
373         }
374
375         org = realorigin(self.enemy);
376         makevectors(self.v_angle);
377
378         // decide if I should shoot
379
380         foedist = vlen(org - self.origin);
381         v = weapon_range(self.weapon);
382         if (foedist > v_y && foedist < v_z)
383         {
384                 traceline(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * v_z, FALSE, self);
385                 if (vlen(trace_endpos - (self.origin + self.view_ofs)) >= v_y)
386                 {
387                         // try to avoid shooting teammates
388                         if (trace_ent.classname == "player")
389                                 if ((trace_ent.team == self.team && teamplay) || (coop))
390                                         return;
391                         bot_shoot();
392                 }
393         }
394         else
395                 bot_weapon_switch(foedist);
396
397         if (!(self.b_aiflags & (AI_PRECISION | AI_BLIND | AI_OBSTRUCTED)))
398         {
399                 foesz = bot_size_player(self.enemy);
400                 mysz = bot_size_player(self) + 5;
401
402                 if (foesz > mysz)
403                 {
404                         if (teamplay)
405                         {
406                                 if (random() < 0.02)
407                                 {
408                                         bot_start_topic(5);
409                                         self.b_chattime = 1;
410                                 }
411                         }
412                         
413                         return;
414                 }
415                 else if (mysz < 140)
416                         return;
417                 else if (self.avoid)
418                 {
419                         if (self.avoid.velocity)
420                                 v = self.avoid.velocity;
421                         else
422                                 v = normalize(self.avoid.origin - self.origin);
423                         v1_x = v_y;
424                         v1_y = v_y * -1;
425                         v2_x = v_y;
426                         v2_y = v_y * -1;
427                         foedist = vlen(self.avoid.origin - (self.origin + v1));
428                         if (foedist < vlen(self.avoid.origin - (self.origin + v2)))
429                                 frik_walkmove(v2);
430                         else
431                                 frik_walkmove(v1);
432                 }
433                 else if (!self.enemy.flags & FL_MONSTER)
434                 {
435                         if (foedist + 32 <  v_x)
436                                 frik_walkmove(self.origin - org);
437                         else if (foedist - 32 >  v_x)
438                                 frik_walkmove(org - self.origin);
439                         else if (self.wallhug)
440                                 frik_walkmove(v_right);
441                         else
442                                 frik_walkmove(v_right * -1);
443                 }
444         }
445         else
446         {
447                 foesz = bot_size_player(self.enemy);
448                 mysz = bot_size_player(self) + 5;
449
450                 if (foesz > mysz)
451                         return;
452                 else if (mysz < 140)
453                         return;
454                 self.keys = self.keys & 960;
455         }
456 };
457
458