2 .float havocbot_role_timeout;
3 .void() havocbot_previous_role;
4 .float bot_strategytime;
8 float(entity e) canreach =
10 return vlen(self.origin - e.origin) < 1500;
13 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items =
17 ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
18 head = findchainfloat(bot_pickup, TRUE);
21 if (head.solid) // must be possible to pick up (respawning items don't count)
22 if (vlen(head.origin - org) < sradius)
25 //if (!head.bot_pickupevalfunc || head.model == "")
27 // get the value of the item
28 t = head.bot_pickupevalfunc(self, head);
30 navigation_routerating(head, t * ratingscale);
36 void(float ratingscale, vector org, float sradius) havocbot_goalrating_controlpoints =
39 head = findchain(classname, "dom_controlpoint");
42 if (vlen(head.origin - org) < sradius)
44 if(head.cnt > -1) // this is just being fought for
45 navigation_routerating(head, ratingscale);
46 else if(head.goalentity.cnt == 0) // unclaimed point
47 navigation_routerating(head, ratingscale * 0.5);
48 else if(head.goalentity.team != self.team) // other team's point
49 navigation_routerating(head, ratingscale * 0.2);
56 // LordHavoc: this function was already unused, but for waypoints to be a
57 // useful goal the bots would have to seek out the least-recently-visited
58 // ones, not the closest
59 void(float ratingscale, vector org, float sradius) havocbot_goalrating_waypoints =
62 head = findchain(classname, "waypoint");
65 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
66 navigation_routerating(head, ratingscale);
72 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers =
75 local float t, noteam;
76 noteam = ((self.team == 0) || (teamplay == 0)); // fteqcc sucks
77 //dprint("teamplay is "); dprint(ftos(teamplay)); dprint(", own team is ");
78 //dprint(ftos(self.team)); dprint(" -> noteam is "); dprint(ftos(noteam));
85 if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
86 if (vlen(head.origin - org) < sradius)
88 t = 100 / (head.health + head.armorvalue);
91 //dprint("found: "); dprint(head.netname); dprint("\n");
92 navigation_routerating(head, t * ratingscale);
99 void() havocbot_role_ctf_middle;
100 void() havocbot_role_ctf_defense;
101 void() havocbot_role_ctf_offense;
102 void() havocbot_role_ctf_interceptor;
104 void(float ratingscale, vector org, float sradius) havocbot_goalrating_ctf_carrieritems =
108 head = findchainfloat(bot_pickup, TRUE);
111 // look for health and armor only
112 if (head.solid) // must be possible to pick up (respawning items don't count)
113 if (head.health || head.armorvalue)
114 if (vlen(head.origin - org) < sradius)
117 //if (!head.bot_pickupevalfunc || head.model == "")
119 // get the value of the item
120 t = head.bot_pickupevalfunc(self, head) * 0.0001;
122 navigation_routerating(head, t * ratingscale);
128 void(float ratingscale) havocbot_goalrating_ctf_ourflag =
131 if (self.team == COLOR_TEAM1) // red
132 head = find(world, classname, "item_flag_team1"); // red flag
134 head = find(world, classname, "item_flag_team2"); // blue flag
135 navigation_routerating(head, ratingscale);
138 void(float ratingscale) havocbot_goalrating_ctf_enemyflag =
141 if (self.team == COLOR_TEAM1) // red
142 head = find(world, classname, "item_flag_team2"); // blue flag
144 head = find(world, classname, "item_flag_team1"); // red flag
145 navigation_routerating(head, ratingscale);
148 void(float ratingscale) havocbot_goalrating_ctf_enemybase =
150 // div0: needs a change in the CTF code
153 void(float ratingscale) havocbot_goalrating_ctf_ourstolenflag =
156 if (self.team == COLOR_TEAM1) // red
157 head = find(world, classname, "item_flag_team1"); // red flag
159 head = find(world, classname, "item_flag_team2"); // blue flag
160 if (head.cnt != FLAG_BASE)
161 navigation_routerating(head, ratingscale);
164 void(float ratingscale) havocbot_goalrating_ctf_droppedflags =
166 local entity redflag, blueflag;
168 redflag = find(world, classname, "item_flag_team1");
169 blueflag = find(world, classname, "item_flag_team2");
171 if (redflag == world)
172 error("havocbot: item_flag_team1 missing\n");
173 if (blueflag == world)
174 error("havocbot: item_flag_team2 missing\n");
176 if (redflag.cnt != FLAG_BASE) // red flag is carried or out in the field
177 navigation_routerating(redflag, ratingscale);
178 if (blueflag.cnt != FLAG_BASE) // blue flag is carried or out in the field
179 navigation_routerating(blueflag, ratingscale);
182 // CTF: (always teamplay)
184 //role rogue: (is this used?)
185 //pick up items and dropped flags (with big rating boost to dropped flags)
186 void() havocbot_role_ctf_rogue =
188 if (self.bot_strategytime < time)
190 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
191 navigation_goalrating_start();
192 havocbot_goalrating_ctf_droppedflags(5000);
193 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
194 havocbot_goalrating_items(10000, self.origin, 10000);
195 navigation_goalrating_end();
200 //pick up armor and health
201 //go to our flag spot
202 void() havocbot_role_ctf_carrier =
204 if (self.flagcarried == world)
206 dprint("changing role to middle\n");
207 self.havocbot_role = havocbot_role_ctf_middle;
208 self.havocbot_role_timeout = 0;
211 if (self.bot_strategytime < time)
213 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
214 navigation_goalrating_start();
215 havocbot_goalrating_ctf_ourflag(5000);
216 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
217 navigation_goalrating_end();
222 //pick up armor and health
223 //if rockets < 25 || health < 100, change role to middle
224 //if carrying flag, change role to flag carrier
225 //if our flag taken, change role to interceptor
226 //(60-90 second timer) change role to middle
228 void() havocbot_role_ctf_offense =
231 if (self.flagcarried)
233 dprint("changing role to carrier\n");
234 self.havocbot_role = havocbot_role_ctf_carrier;
235 self.havocbot_role_timeout = 0;
239 if (self.team == COLOR_TEAM1) // red
240 f = find(world, classname, "item_flag_team1");
242 f = find(world, classname, "item_flag_team2");
243 if (f.cnt != FLAG_BASE && canreach(f))
245 dprint("changing role to interceptor\n");
246 self.havocbot_previous_role = self.havocbot_role;
247 self.havocbot_role = havocbot_role_ctf_interceptor;
248 self.havocbot_role_timeout = 0;
251 if (!self.havocbot_role_timeout)
252 self.havocbot_role_timeout = time + random() * 30 + 60;
253 if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
255 dprint("changing role to middle\n");
256 self.havocbot_role = havocbot_role_ctf_middle;
257 self.havocbot_role_timeout = 0;
260 if (self.bot_strategytime < time)
262 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
263 navigation_goalrating_start();
264 havocbot_goalrating_ctf_ourstolenflag(5000);
265 havocbot_goalrating_ctf_enemyflag(3000);
266 havocbot_goalrating_ctf_enemybase(2000);
267 havocbot_goalrating_items(10000, self.origin, 10000);
268 navigation_goalrating_end();
272 //role interceptor (temporary role):
274 //if carrying flag, change role to flag carrier
275 //if our flag is back, change role to previous role
277 //go to least recently visited area
278 void() havocbot_role_ctf_interceptor =
281 if (self.flagcarried)
283 dprint("changing role to carrier\n");
284 self.havocbot_role = havocbot_role_ctf_carrier;
285 self.havocbot_role_timeout = 0;
289 if (self.team == COLOR_TEAM1) // red
290 f = find(world, classname, "item_flag_team1");
292 f = find(world, classname, "item_flag_team2");
293 if (f.cnt == FLAG_BASE)
295 dprint("changing role back\n");
296 self.havocbot_role = self.havocbot_previous_role;
297 self.havocbot_role_timeout = 0;
301 if (self.bot_strategytime < time)
303 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
304 navigation_goalrating_start();
305 havocbot_goalrating_ctf_ourstolenflag(5000);
306 havocbot_goalrating_ctf_droppedflags(5000);
307 havocbot_goalrating_items(10000, self.origin, 10000);
308 navigation_goalrating_end();
314 //if carrying flag, change role to flag carrier
315 //if our flag taken, change role to interceptor
316 //if see flag (of either team) follow it (this has many implications)
317 //(10-20 second timer) change role to defense or offense
318 //go to least recently visited area
319 void() havocbot_role_ctf_middle =
322 if (self.flagcarried)
324 dprint("changing role to carrier\n");
325 self.havocbot_role = havocbot_role_ctf_carrier;
326 self.havocbot_role_timeout = 0;
330 if (self.team == COLOR_TEAM1) // red
331 f = find(world, classname, "item_flag_team1");
333 f = find(world, classname, "item_flag_team2");
334 if (f.cnt != FLAG_BASE && canreach(f))
336 dprint("changing role to interceptor\n");
337 self.havocbot_previous_role = self.havocbot_role;
338 self.havocbot_role = havocbot_role_ctf_interceptor;
339 self.havocbot_role_timeout = 0;
342 if (!self.havocbot_role_timeout)
343 self.havocbot_role_timeout = time + random() * 10 + 10;
344 if (time > self.havocbot_role_timeout)
345 if (self.ammo_rockets >= 25)
349 dprint("changing role to offense\n");
350 self.havocbot_role = havocbot_role_ctf_offense;
354 dprint("changing role to defense\n");
355 self.havocbot_role = havocbot_role_ctf_defense;
357 self.havocbot_role_timeout = 0;
361 if (self.bot_strategytime < time)
363 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
364 navigation_goalrating_start();
365 havocbot_goalrating_ctf_ourstolenflag(5000);
366 havocbot_goalrating_ctf_droppedflags(3000);
367 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
368 havocbot_goalrating_items(10000, self.origin, 10000);
369 navigation_goalrating_end();
374 //if rockets < 25 || health < 100, change role to middle
375 //if carrying flag, change role to flag carrier
376 //if our flag taken, change role to interceptor
377 //(30-50 second timer) change role to middle
378 //move to nearest unclaimed defense spot
379 void() havocbot_role_ctf_defense =
382 if (self.flagcarried)
384 dprint("changing role to carrier\n");
385 self.havocbot_role = havocbot_role_ctf_carrier;
386 self.havocbot_role_timeout = 0;
390 if (self.team == COLOR_TEAM1) // red
391 f = find(world, classname, "item_flag_team1");
393 f = find(world, classname, "item_flag_team2");
394 if (f.cnt != FLAG_BASE && canreach(f))
396 dprint("changing role to interceptor\n");
397 self.havocbot_previous_role = self.havocbot_role;
398 self.havocbot_role = havocbot_role_ctf_interceptor;
399 self.havocbot_role_timeout = 0;
402 if (!self.havocbot_role_timeout)
403 self.havocbot_role_timeout = time + random() * 20 + 30;
404 if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
406 dprint("changing role to middle\n");
407 self.havocbot_role = havocbot_role_ctf_middle;
408 self.havocbot_role_timeout = 0;
411 if (self.bot_strategytime < time)
413 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
414 navigation_goalrating_start();
415 havocbot_goalrating_ctf_ourstolenflag(20000);
416 havocbot_goalrating_ctf_droppedflags(500);
417 havocbot_goalrating_items(10000, f.origin, 10000);
418 navigation_goalrating_end();
421 // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
422 // change position occasionally
423 if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
425 self.bot_strategytime = time + random() * 45 + 15;
426 self.goalentity = world;
427 head = findchain(classname, "info_ctf_defensepoint");
430 if (time > head.count)
432 self.goalentity = head;
437 // if there are no defensepoints defined, switch to middle
438 if (self.goalentity == world)
440 dprint("changing role to middle\n");
441 self.havocbot_role = havocbot_role_ctf_middle;
442 self.havocbot_role_timeout = 0;
446 // keep anyone else from taking this spot
447 if (self.goalentity != world)
448 self.goalentity.count = time + 0.5;
453 // choose a role according to the situation
454 void() havocbot_chooserole_ctf =
457 dprint("choose CTF role...\n");
458 if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
459 self.havocbot_role = havocbot_role_ctf_rogue;
464 self.havocbot_role = havocbot_role_ctf_offense;
466 self.havocbot_role = havocbot_role_ctf_middle;
468 self.havocbot_role = havocbot_role_ctf_defense;
473 //go to best items, or control points you don't own
474 void() havocbot_role_dom =
476 if (self.bot_strategytime < time)
478 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
479 navigation_goalrating_start();
480 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
481 havocbot_goalrating_items(8000, self.origin, 8000);
482 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
483 //havocbot_goalrating_waypoints(1, self.origin, 1000);
484 navigation_goalrating_end();
490 void() havocbot_role_dm =
492 if (self.bot_strategytime < time)
494 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
495 navigation_goalrating_start();
496 havocbot_goalrating_items(10000, self.origin, 10000);
497 havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
498 //havocbot_goalrating_waypoints(1, self.origin, 1000);
499 navigation_goalrating_end();
503 void() havocbot_chooserole_dm =
505 self.havocbot_role = havocbot_role_dm;
508 void() havocbot_chooserole_dom =
510 self.havocbot_role = havocbot_role_dom;
518 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
521 for(head = world; (head = find(head, classname, "item_kh_key")); )
523 if(head.owner == self)
525 if(!kh_tracking_enabled)
526 if(!head.owner || head.team == self.team)
527 continue; // skip what I can't see
529 navigation_routerating(head, ratingscale_dropped);
530 else if(head.team == self.team)
531 navigation_routerating(head, ratingscale_team);
533 navigation_routerating(head, ratingscale_enemy);
537 void() havocbot_role_kh_carrier;
538 void() havocbot_role_kh_defense;
539 void() havocbot_role_kh_offense;
540 void() havocbot_role_kh_freelancer;
541 void() havocbot_role_kh_carrier =
543 if (!(self.items & IT_KEY1))
545 dprint("changing role to freelancer\n");
546 self.havocbot_role = havocbot_role_kh_freelancer;
547 self.havocbot_role_timeout = 0;
551 if (self.bot_strategytime < time)
553 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
554 navigation_goalrating_start();
556 if(kh_Key_AllOwnedByWhichTeam() == self.team)
557 havocbot_goalrating_kh(10000, 1, 1); // bring home
559 havocbot_goalrating_kh(4000, 4000, 100); // play defensively
561 havocbot_goalrating_items(10000, self.origin, 10000);
562 navigation_goalrating_end();
566 void() havocbot_role_kh_defense =
568 if (self.items & IT_KEY1)
570 dprint("changing role to carrier\n");
571 self.havocbot_role = havocbot_role_kh_carrier;
572 self.havocbot_role_timeout = 0;
576 if (!self.havocbot_role_timeout)
577 self.havocbot_role_timeout = time + random() * 10 + 20;
578 if (time > self.havocbot_role_timeout)
580 dprint("changing role to freelancer\n");
581 self.havocbot_role = havocbot_role_kh_freelancer;
582 self.havocbot_role_timeout = 0;
586 if (self.bot_strategytime < time)
588 float key_owner_team;
589 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
590 navigation_goalrating_start();
592 key_owner_team = kh_Key_AllOwnedByWhichTeam();
593 if(key_owner_team == self.team)
594 havocbot_goalrating_kh(10000, 1, 1); // defend key carriers
595 else if(key_owner_team == -1)
596 havocbot_goalrating_kh(4000, 1000, 1); // play defensively
598 havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
600 havocbot_goalrating_items(10000, self.origin, 10000);
601 navigation_goalrating_end();
605 void() havocbot_role_kh_offense =
607 if (self.items & IT_KEY1)
609 dprint("changing role to carrier\n");
610 self.havocbot_role = havocbot_role_kh_carrier;
611 self.havocbot_role_timeout = 0;
615 if (!self.havocbot_role_timeout)
616 self.havocbot_role_timeout = time + random() * 10 + 20;
617 if (time > self.havocbot_role_timeout)
619 dprint("changing role to freelancer\n");
620 self.havocbot_role = havocbot_role_kh_freelancer;
621 self.havocbot_role_timeout = 0;
625 if (self.bot_strategytime < time)
627 float key_owner_team;
629 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
630 navigation_goalrating_start();
632 key_owner_team = kh_Key_AllOwnedByWhichTeam();
633 if(key_owner_team == self.team)
634 havocbot_goalrating_kh(10000, 1, 1); // defend anyway
635 else if(key_owner_team == -1)
636 havocbot_goalrating_kh(1, 1000, 4000); // play offensively
638 havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
640 havocbot_goalrating_items(10000, self.origin, 10000);
641 navigation_goalrating_end();
645 void() havocbot_role_kh_freelancer =
647 if (self.items & IT_KEY1)
649 dprint("changing role to carrier\n");
650 self.havocbot_role = havocbot_role_kh_carrier;
651 self.havocbot_role_timeout = 0;
655 if (!self.havocbot_role_timeout)
656 self.havocbot_role_timeout = time + random() * 10 + 10;
657 if (time > self.havocbot_role_timeout)
661 dprint("changing role to offense\n");
662 self.havocbot_role = havocbot_role_kh_offense;
666 dprint("changing role to defense\n");
667 self.havocbot_role = havocbot_role_kh_defense;
669 self.havocbot_role_timeout = 0;
673 if (self.bot_strategytime < time)
675 float key_owner_team;
677 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
678 navigation_goalrating_start();
680 key_owner_team = kh_Key_AllOwnedByWhichTeam();
681 if(key_owner_team == self.team)
682 havocbot_goalrating_kh(10000, 1, 1); // defend anyway
683 else if(key_owner_team == -1)
684 havocbot_goalrating_kh(1000, 4000, 1000); // prefer dropped keys
686 havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
688 havocbot_goalrating_items(10000, self.origin, 10000);
689 navigation_goalrating_end();
697 void() havocbot_chooserole_kh =
702 self.havocbot_role = havocbot_role_kh_offense;
704 self.havocbot_role = havocbot_role_kh_defense;
706 self.havocbot_role = havocbot_role_kh_freelancer;
709 void() havocbot_chooserole =
711 dprint("choose a role...\n");
712 navigation_routetogoal(world);
713 self.bot_strategytime = -1;
715 havocbot_chooserole_ctf();
716 else if (g_domination)
717 havocbot_chooserole_dom();
719 havocbot_chooserole_kh();
720 else // assume anything else is deathmatch
721 havocbot_chooserole_dm();