1 /***********************************************
\r
3 * FrikBot Fight Code *
\r
4 * "Because I ain't no Ghandi code" *
\r
6 ***********************************************/
\r
10 This program is in the Public Domain. My crack legal
\r
11 team would like to add:
\r
13 RYAN "FRIKAC" SMITH IS PROVIDING THIS SOFTWARE "AS IS"
\r
14 AND MAKES NO WARRANTY, EXPRESS OR IMPLIED, AS TO THE
\r
15 ACCURACY, CAPABILITY, EFFICIENCY, MERCHANTABILITY, OR
\r
16 FUNCTIONING OF THIS SOFTWARE AND/OR DOCUMENTATION. IN
\r
17 NO EVENT WILL RYAN "FRIKAC" SMITH BE LIABLE FOR ANY
\r
18 GENERAL, CONSEQUENTIAL, INDIRECT, INCIDENTAL,
\r
19 EXEMPLARY, OR SPECIAL DAMAGES, EVEN IF RYAN "FRIKAC"
\r
20 SMITH HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
\r
21 DAMAGES, IRRESPECTIVE OF THE CAUSE OF SUCH DAMAGES.
\r
23 You accept this software on the condition that you
\r
24 indemnify and hold harmless Ryan "FrikaC" Smith from
\r
25 any and all liability or damages to third parties,
\r
26 including attorney fees, court costs, and other
\r
27 related costs and expenses, arising out of your use
\r
28 of this software irrespective of the cause of said
\r
31 The export from the United States or the subsequent
\r
32 reexport of this software is subject to compliance
\r
33 with United States export control and munitions
\r
34 control restrictions. You agree that in the event you
\r
35 seek to export this software, you assume full
\r
36 responsibility for obtaining all necessary export
\r
37 licenses and approvals and for assuring compliance
\r
38 with applicable reexport restrictions.
\r
40 Any reproduction of this software must contain
\r
41 this notice in its entirety.
\r
47 float(entity e) bot_size_player =
\r
51 sz = e.health + e.armorvalue * e.armortype;
\r
52 if (e.weapon == WEP_ROCKET_LAUNCHER)
\r
54 else if (e.weapon == WEP_HAGAR)
\r
56 else if (e.weapon == WEP_NEX)
\r
58 else if (e.weapon == WEP_CRYLINK)
\r
60 else if (e.weapon == WEP_ELECTRO)
\r
62 else if (e.weapon == WEP_GRENADE_LAUNCHER)
\r
64 else if (e.weapon == WEP_UZI)
\r
66 else if (e.weapon == WEP_SHOTGUN)
\r
68 else if (e.weapon == WEP_LASER)
\r
70 if (e.items & 4194304) // Quad
\r
72 if (e.items & 1048576) // Invul
\r
74 if (e.items & 524288) // Invis
\r
79 void() bot_dodge_stuff =
\r
82 local float foedist, avdist, foesz, flen, tsz;
\r
85 if (waypoint_mode > WM_LOADED)
\r
93 v = self.origin - realorigin(self.enemy);
\r
95 foesz = bot_size_player(self.enemy);
\r
104 foe = find(world, classname, "grenade");
\r
107 flen = vlen(foe.origin - self.origin);
\r
113 foe = find(foe, classname, "grenade");
\r
117 foe = find(world, classname, "missile");
\r
120 if (foe.owner != self)
\r
122 flen = vlen(foe.origin - self.origin);
\r
129 foe = find(foe, classname, "missile");
\r
133 foe = find(world, classname, "spike");
\r
136 if (foe.owner != self)
\r
138 flen = vlen(foe.origin - self.origin);
\r
145 foe = find(foe, classname, "spike");
\r
153 foe = findradius(self.origin, foedist);
\r
156 if(foe.flags & FL_MONSTER)
\r
160 flen = vlen(foe.origin - self.origin);
\r
161 if (flen < foedist)
\r
163 tsz = bot_size_player(foe);
\r
187 if (foe.modelindex != 0)
\r
189 if (foe.health > 0)
\r
191 if (!(teamplay && self.team == foe.team))
\r
193 flen = vlen(foe.origin - self.origin);
\r
194 if (flen < foedist)
\r
196 tsz = bot_size_player(foe);
\r
199 if (fov(foe) || foe.b_sound > time || self.b_skill == 3)
\r
204 foedist = vlen(foe.origin - self.origin);
\r
222 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
226 _x "sweet spot range" - try to maintain this range if possible
\r
227 _y minimum range bot can be to be effective (rl/gl) (move away)
\r
228 _z maximum range bot can be to be effective (lg/axe) (move in)
\r
229 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
232 vector(float wep) weapon_range =
\r
234 if (wep == IT_LASER) // IT_AXE
\r
236 else if (wep == IT_SHOTGUN) // IT_SHOTGUN
\r
237 return '128 0 99999';
\r
238 else if (wep == IT_CRYLINK) // IT_SUPER_SHOTGUN
\r
239 return '128 0 99999';
\r
240 else if (wep == IT_UZI) // IT_NAILGUN
\r
241 return '180 0 3000';
\r
242 else if (wep == IT_HAGAR) // IT_SUPER_NAILGUN
\r
243 return '180 48 3000';
\r
244 else if (wep == IT_GRENADE_LAUNCHER) // IT_GRENADE_LAUNCHER
\r
245 return '180 48 3000';
\r
246 else if (wep == IT_ELECTRO) // IT_ROCKET_LAUNCHER
\r
247 return '180 48 3000';
\r
248 else if (wep == IT_ROCKET_LAUNCHER) // IT_ROCKET_LAUNCHER
\r
249 return '180 48 3000';
\r
250 else if (wep == IT_NEX) // IT_LIGHTNING
\r
251 return '350 0 99999';
\r
256 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
260 Pick a weapon based on range / ammo
\r
262 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
265 void(float brange) bot_weapon_switch =
\r
267 local float it, flag, pulse;
\r
270 it = self.items & 127;
\r
275 if ((self.ammo_rockets >= 3) && (it & IT_ROCKET_LAUNCHER)){flag = IT_ROCKET_LAUNCHER;pulse = 9;}
\r
276 else if ((self.ammo_rockets >= 1) && (it & IT_HAGAR)){flag = IT_HAGAR;pulse = 8;}
\r
277 else if ((self.ammo_cells >= 5) && (it & IT_NEX)){flag = IT_NEX;pulse = 7;}
\r
278 else if ((self.ammo_cells >= 1) && (it & IT_CRYLINK)){flag = IT_CRYLINK;pulse = 6;}
\r
279 else if ((self.ammo_cells >= 2) && (it & IT_ELECTRO)){flag = IT_ELECTRO;pulse = 5;}
\r
280 else if ((self.ammo_rockets >= 3) && (it & IT_GRENADE_LAUNCHER)){flag = IT_GRENADE_LAUNCHER;pulse = 4;}
\r
281 else if ((self.ammo_nails >= 1) && (it & IT_UZI)){flag = IT_UZI;pulse = 3;}
\r
282 else if ((self.ammo_shells >= 1) && (it & IT_SHOTGUN)){flag = IT_SHOTGUN;pulse = 2;}
\r
286 self.impulse = pulse;
\r
293 self.impulse = pulse;
\r
297 v = weapon_range(flag);
\r
298 if (brange < v_y || brange > v_z)
\r
303 self.impulse = pulse;
\r
311 // quick little function to stop making him shoot the wrong way ! Argh
\r
313 g = angcomp(self.v_angle_x, self.b_angle_x);
\r
315 return; // argh, too far away
\r
316 g = angcomp(self.v_angle_y, self.b_angle_y);
\r
318 return; // not again!
\r
319 self.button0 = TRUE;
\r
323 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
327 This is the core of the bot's thinking when
\r
328 attacking an enemy.
\r
330 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
\r
333 void() bot_fight_style =
\r
335 local vector v, v1, v2, org;
\r
336 local float foedist, mysz, foesz;
\r
339 if (self.enemy.health <= 0)
\r
341 self.enemy = world;
\r
344 else if (!self.enemy.takedamage)
\r
346 self.enemy = world;
\r
349 else if (!fisible(self.enemy))
\r
351 self.enemy = world;
\r
355 org = realorigin(self.enemy);
\r
356 makevectors(self.v_angle);
\r
358 // decide if I should shoot
\r
360 foedist = vlen(org - self.origin);
\r
361 v = weapon_range(self.weapon);
\r
362 if (foedist > v_y && foedist < v_z)
\r
364 traceline(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * v_z, FALSE, self);
\r
365 if (vlen(trace_endpos - (self.origin + self.view_ofs)) >= v_y)
\r
367 // try to avoid shooting teammates
\r
368 if (trace_ent.classname == "player")
\r
369 if ((trace_ent.team == self.team && teamplay) || (coop))
\r
375 bot_weapon_switch(foedist);
\r
377 if (!(self.b_aiflags & (AI_PRECISION | AI_BLIND | AI_OBSTRUCTED)))
\r
379 foesz = bot_size_player(self.enemy);
\r
380 mysz = bot_size_player(self) + 5;
\r
386 if (random() < 0.02)
\r
388 bot_start_topic(5);
\r
389 self.b_chattime = 1;
\r
395 else if (mysz < 140)
\r
397 else if (self.avoid)
\r
399 if (self.avoid.velocity)
\r
400 v = self.avoid.velocity;
\r
402 v = normalize(self.avoid.origin - self.origin);
\r
407 foedist = vlen(self.avoid.origin - (self.origin + v1));
\r
408 if (foedist < vlen(self.avoid.origin - (self.origin + v2)))
\r
413 else if (!self.enemy.flags & FL_MONSTER)
\r
415 if (foedist + 32 < v_x)
\r
416 frik_walkmove(self.origin - org);
\r
417 else if (foedist - 32 > v_x)
\r
418 frik_walkmove(org - self.origin);
\r
419 else if (self.wallhug)
\r
420 frik_walkmove(v_right);
\r
422 frik_walkmove(v_right * -1);
\r
427 foesz = bot_size_player(self.enemy);
\r
428 mysz = bot_size_player(self) + 5;
\r
432 else if (mysz < 140)
\r
434 self.keys = self.keys & 960;
\r