]> icculus.org git repositories - divverent/nexuiz.git/blob - qcsrc/gamec/bot_fight.c
bots now know the nexuiz weapons
[divverent/nexuiz.git] / qcsrc / gamec / bot_fight.c
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 == WEP_ROCKET_LAUNCHER)
53                 sz = sz + 60;
54         else if (e.weapon == WEP_HAGAR)
55                 sz = sz + 60;
56         else if (e.weapon == WEP_NEX)
57                 sz = sz + 60;
58         else if (e.weapon == WEP_CRYLINK)
59                 sz = sz + 50;
60         else if (e.weapon == WEP_ELECTRO)
61                 sz = sz + 50;
62         else if (e.weapon == WEP_GRENADE_LAUNCHER)
63                 sz = sz + 40;
64         else if (e.weapon == WEP_UZI)
65                 sz = sz + 40;
66         else if (e.weapon == WEP_SHOTGUN)
67                 sz = sz + 10;
68         else if (e.weapon == WEP_LASER)
69                 sz = sz - 50;
70         if (e.items & 4194304) // Quad
71                 sz = sz + 200;
72         if (e.items & 1048576) // Invul
73                 sz = sz + 300;
74         if (e.items & 524288) // Invis
75                 sz = sz + 250;
76         return sz;
77 };
78
79 void() bot_dodge_stuff =
80 {
81         local entity foe;
82         local float foedist, avdist, scandist, foesz, flen, tsz;
83         local vector v;
84
85         if (waypoint_mode > WM_LOADED)
86                 return;
87
88         self.avoid = world;
89
90
91         if (self.enemy)
92         {
93                 v = self.origin - realorigin(self.enemy);
94                 foedist = vlen(v);
95                 foesz = bot_size_player(self.enemy);
96         }
97         else
98         {
99                 foedist = 3000;
100                 foesz = 9999999;
101         }
102         avdist = 256;
103
104         foe = find(world, classname, "grenade");
105         while(foe)
106         {
107                 flen = vlen(foe.origin - self.origin);
108                 if (flen < avdist)
109                 {
110                         avdist = flen;
111                         self.avoid = foe;
112                 }
113                 foe = find(foe, classname, "grenade");
114         }
115         if (!self.avoid)
116         {
117                 foe = find(world, classname, "missile");
118                 while(foe)
119                 {
120                         if (foe.owner != self)
121                         {
122                                 flen = vlen(foe.origin - self.origin);
123                                 if (flen < avdist)
124                                 {
125                                         avdist = flen;
126                                         self.avoid = foe;
127                                 }
128                         }
129                         foe = find(foe, classname, "missile");
130                 }
131                 if (!self.avoid)
132                 {
133                         foe = find(world, classname, "spike");
134                         while(foe)
135                         {
136                                 if (foe.owner != self)
137                                 {
138                                         flen = vlen(foe.origin - self.origin);
139                                         if (flen < avdist)
140                                         {
141                                                 avdist = flen;
142                                                 self.avoid = foe;
143                                         }
144                                 }
145                                 foe = find(foe, classname, "spike");
146                         }
147                 }
148         }
149         if (coop)
150         {
151                 if (!self.enemy)
152                 {
153                         foe = findradius(self.origin, foedist);
154                         while(foe)
155                         {
156                                 if(foe.flags & FL_MONSTER)
157                                 {
158                                         if(foe.health > 0)
159                                         {
160                                                 flen = vlen(foe.origin - self.origin);
161                                                 if (flen < foedist)
162                                                 {
163                                                         tsz = bot_size_player(foe);
164                                                         if (tsz < foesz)
165                                                         {
166                                                                 if (fisible(foe))
167                                                                 {
168                                                                         self.enemy = foe;
169                                                                         foedist = flen;
170                                                                         foesz = tsz;
171                                                                 }
172                                                         }
173                                                 }
174                                         }
175                                 }
176                                 foe = foe.chain;
177                         }
178                 }
179         }
180         else
181         {
182                 foe = player_head;
183                 while(foe)
184                 {
185                         if(foe != self)
186                         {
187                                 if (foe.modelindex != 0)
188                                 {
189                                         if (foe.health > 0)
190                                         {
191                                                 if (!(teamplay && self.team == foe.team))
192                                                 {
193                                                         flen = vlen(foe.origin - self.origin);
194                                                         if (flen < foedist)
195                                                         {
196                                                                 tsz = bot_size_player(foe);
197                                                                 if (tsz < foesz)
198                                                                 {
199                                                                         if (fov(foe) || foe.b_sound > time || self.b_skill == 3)
200                                                                         {
201                                                                                 if (fisible(foe))
202                                                                                 {
203                                                                                         self.enemy = foe;
204                                                                                         foedist = vlen(foe.origin - self.origin);
205                                                                                 }
206                                                                         }
207                                                                 }
208                                                         }
209                                                 }
210                                         }
211                                 }
212                         }
213                         foe = foe._next;
214                 }
215         }
216 };
217
218
219
220
221 /*
222 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
223
224 weapon_range
225
226 _x "sweet spot range" - try to maintain this range if possible
227 _y minimum range bot can be to be effective (rl/gl) (move away)
228 _z maximum range bot can be to be effective (lg/axe) (move in)
229 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
230 */
231
232 vector(float wep) weapon_range =
233 {
234         if (wep == WEP_LASER) // IT_AXE
235                 return '48 0 300';
236         else if (wep == WEP_SHOTGUN) // IT_SHOTGUN
237                 return '128 0 99999';
238         else if (wep == WEP_CRYLINK) // IT_SUPER_SHOTGUN
239                 return '128 0 99999';
240         else if (wep == WEP_UZI) // IT_NAILGUN
241                 return '180 0 3000';
242         else if (wep == WEP_HAGAR) // IT_SUPER_NAILGUN
243                 return '180 48 3000';
244         else if (wep == WEP_GRENADE_LAUNCHER) // IT_GRENADE_LAUNCHER
245                 return '180 48 3000';
246         else if (wep == WEP_ELECTRO) // IT_ROCKET_LAUNCHER
247                 return '180 48 3000';
248         else if (wep == WEP_ROCKET_LAUNCHER) // IT_ROCKET_LAUNCHER
249                 return '180 48 3000';
250         else if (wep == WEP_NEX) // IT_LIGHTNING
251                 return '350 0 99999';
252 };
253 /*
254 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
255
256 bot_weapon_switch
257
258 Pick a weapon based on range / ammo
259
260 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
261 */
262
263 void(float brange) bot_weapon_switch =
264 {
265         local   float   it, flag, pulse;
266         local vector v;
267
268         it = self.items & 127;
269
270         while(it)
271         {
272                 if ((self.ammo_rockets >= 1) && (it & 32))
273                 {
274                         flag = 32;
275                         pulse = 7;
276                 }
277                 else if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & 64))
278                 {
279                         flag = 64;
280                         pulse = 8;
281                 }
282                 else if(self.ammo_nails >= 2 && (it & 8))
283                 {
284                         flag = 8;
285                         pulse = 5;
286                 }
287                 else if ((self.ammo_rockets >= 1) && (it & 16))
288                 {
289                         flag = 16;
290                         pulse = 6;
291                 }
292                 else if(self.ammo_shells >= 2 && (it & 2))
293                 {
294                         flag = 2;
295                         pulse = 3;
296                 }
297                 else if(self.ammo_nails >= 1 && (it & 4))
298                 {
299                         flag = 4;
300                         pulse = 4;
301                 }
302                 else if(self.ammo_shells >= 1 && (it & 1))
303                 {
304                         flag = 1;
305                         pulse = 2;
306                 }
307                 else
308                 {
309                         if (pulse)
310                                 self.impulse = pulse;
311                         return;
312                 }
313
314                 if (brange == -1)
315                 {
316                         if (pulse)
317                                 self.impulse = pulse;
318                         return;
319                 }
320
321                 v = weapon_range(flag);
322                 if (brange < v_y || brange > v_z)
323                         it = it - flag;
324                 else
325                 {
326                         if (pulse)
327                                 self.impulse = pulse;
328                         return;
329                 }
330         }
331 };
332
333 void() bot_shoot =
334 {
335         // quick little function to stop making him shoot the wrong way ! Argh
336         local float g;
337         g = angcomp(self.v_angle_x, self.b_angle_x);
338         if (fabs(g) > 30)
339                 return; // argh, too far away
340         g = angcomp(self.v_angle_y, self.b_angle_y);
341         if (fabs(g) > 30)
342                 return; // not again!
343         self.button0 = TRUE;
344 };
345
346 /*
347 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
348
349 Bot_fight_style
350
351 This is the core of the bot's thinking when
352 attacking an enemy.
353
354 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
355 */
356
357 void() bot_fight_style =
358 {
359         local vector v, v1, v2, org;
360         local float foedist, mysz, foesz;
361
362
363         if (self.enemy.health <= 0)
364         {
365                 self.enemy = world;
366                 return;
367         }
368         else if (!self.enemy.takedamage)
369         {
370                 self.enemy = world;
371                 return;
372         }
373         else if (!fisible(self.enemy))
374         {
375                 self.enemy = world;
376                 return;
377         }
378
379         org = realorigin(self.enemy);
380         makevectors(self.v_angle);
381
382         // decide if I should shoot
383
384         foedist = vlen(org - self.origin);
385         v = weapon_range(self.weapon);
386         if (foedist > v_y && foedist < v_z)
387         {
388                 traceline(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * v_z, FALSE, self);
389                 if (vlen(trace_endpos - (self.origin + self.view_ofs)) >= v_y)
390                 {
391                         // try to avoid shooting teammates
392                         if (trace_ent.classname == "player")
393                                 if ((trace_ent.team == self.team && teamplay) || (coop))
394                                         return;
395                         bot_shoot();
396                 }
397         }
398         else
399                 bot_weapon_switch(foedist);
400
401         if (!(self.b_aiflags & (AI_PRECISION | AI_BLIND | AI_OBSTRUCTED)))
402         {
403                 foesz = bot_size_player(self.enemy);
404                 mysz = bot_size_player(self) + 5;
405
406                 if (foesz > mysz)
407                 {
408                         if (teamplay)
409                         {
410                                 if (random() < 0.02)
411                                 {
412                                         bot_start_topic(5);
413                                         self.b_chattime = 1;
414                                 }
415                         }
416
417                         return;
418                 }
419                 else if (mysz < 140)
420                         return;
421                 else if (self.avoid)
422                 {
423                         if (self.avoid.velocity)
424                                 v = self.avoid.velocity;
425                         else
426                                 v = normalize(self.avoid.origin - self.origin);
427                         v1_x = v_y;
428                         v1_y = v_y * -1;
429                         v2_x = v_y;
430                         v2_y = v_y * -1;
431                         foedist = vlen(self.avoid.origin - (self.origin + v1));
432                         if (foedist < vlen(self.avoid.origin - (self.origin + v2)))
433                                 frik_walkmove(v2);
434                         else
435                                 frik_walkmove(v1);
436                 }
437                 else if (!self.enemy.flags & FL_MONSTER)
438                 {
439                         if (foedist + 32 <  v_x)
440                                 frik_walkmove(self.origin - org);
441                         else if (foedist - 32 >  v_x)
442                                 frik_walkmove(org - self.origin);
443                         else if (self.wallhug)
444                                 frik_walkmove(v_right);
445                         else
446                                 frik_walkmove(v_right * -1);
447                 }
448         }
449         else
450         {
451                 foesz = bot_size_player(self.enemy);
452                 mysz = bot_size_player(self) + 5;
453
454                 if (foesz > mysz)
455                         return;
456                 else if (mysz < 140)
457                         return;
458                 self.keys = self.keys & 960;
459         }
460 };
461
462