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, 2000);
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, 5000);
46 else if(head.goalentity.cnt == 0) // unclaimed point
47 navigation_routerating(head, ratingscale * 0.5, 5000);
48 else if(head.goalentity.team != self.team) // other team's point
49 navigation_routerating(head, ratingscale * 0.2, 5000);
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, 2000);
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, 500);
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, 500);
129 void(float ratingscale) havocbot_goalrating_ctf_ourflag =
135 if (self.team == head.team)
140 navigation_routerating(head, ratingscale, 10000);
143 void(float ratingscale) havocbot_goalrating_ctf_enemyflag =
149 if (self.team != head.team)
154 navigation_routerating(head, ratingscale, 10000);
157 void(float ratingscale) havocbot_goalrating_ctf_enemybase =
159 // div0: needs a change in the CTF code
162 void(float ratingscale) havocbot_goalrating_ctf_ourstolenflag =
168 if (self.team == head.team)
173 if (head.cnt != FLAG_BASE)
174 navigation_routerating(head, ratingscale, 10000);
177 void(float ratingscale) havocbot_goalrating_ctf_droppedflags =
183 if (head.cnt != FLAG_BASE) // flag is carried or out in the field
184 navigation_routerating(head, ratingscale, 10000);
189 // CTF: (always teamplay)
191 //role rogue: (is this used?)
192 //pick up items and dropped flags (with big rating boost to dropped flags)
193 void() havocbot_role_ctf_rogue =
195 if (self.bot_strategytime < time)
197 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
198 navigation_goalrating_start();
199 havocbot_goalrating_ctf_droppedflags(5000);
200 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
201 havocbot_goalrating_items(10000, self.origin, 10000);
202 navigation_goalrating_end();
207 //pick up armor and health
208 //go to our flag spot
209 .float bot_cantfindflag;
210 void() havocbot_role_ctf_carrier =
212 if (self.flagcarried == world)
214 dprint("changing role to middle\n");
215 self.havocbot_role = havocbot_role_ctf_middle;
216 self.havocbot_role_timeout = 0;
219 if (self.bot_strategytime < time)
221 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
222 navigation_goalrating_start();
223 havocbot_goalrating_ctf_ourflag(50000);
224 if (navigation_bestgoal)
225 self.bot_cantfindflag = time + 10;
226 else if (time > self.bot_cantfindflag)
228 // can't navigate to our own flag :(
229 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
231 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
232 navigation_goalrating_end();
237 //pick up armor and health
238 //if rockets < 25 || health < 100, change role to middle
239 //if carrying flag, change role to flag carrier
240 //if our flag taken, change role to interceptor
241 //(60-90 second timer) change role to middle
243 void() havocbot_role_ctf_offense =
246 if (self.flagcarried)
248 dprint("changing role to carrier\n");
249 self.havocbot_role = havocbot_role_ctf_carrier;
250 self.havocbot_role_timeout = 0;
251 self.bot_cantfindflag = time + 10;
258 if (self.team == f.team)
262 if (f.cnt != FLAG_BASE && canreach(f))
264 dprint("changing role to interceptor\n");
265 self.havocbot_previous_role = self.havocbot_role;
266 self.havocbot_role = havocbot_role_ctf_interceptor;
267 self.havocbot_role_timeout = 0;
270 if (!self.havocbot_role_timeout)
271 self.havocbot_role_timeout = time + random() * 30 + 60;
272 if (time > self.havocbot_role_timeout)
274 dprint("changing role to middle\n");
275 self.havocbot_role = havocbot_role_ctf_middle;
276 self.havocbot_role_timeout = 0;
279 if (self.bot_strategytime < time)
281 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
282 navigation_goalrating_start();
283 havocbot_goalrating_ctf_ourstolenflag(50000);
284 havocbot_goalrating_ctf_enemyflag(30000);
285 havocbot_goalrating_ctf_enemybase(20000);
286 havocbot_goalrating_items(10000, self.origin, 10000);
287 navigation_goalrating_end();
291 //role interceptor (temporary role):
293 //if carrying flag, change role to flag carrier
294 //if our flag is back, change role to previous role
296 //go to least recently visited area
297 void() havocbot_role_ctf_interceptor =
300 if (self.flagcarried)
302 dprint("changing role to carrier\n");
303 self.havocbot_role = havocbot_role_ctf_carrier;
304 self.havocbot_role_timeout = 0;
305 self.bot_cantfindflag = time + 10;
312 if (self.team == f.team)
316 if (f.cnt == FLAG_BASE)
318 dprint("changing role back\n");
319 self.havocbot_role = self.havocbot_previous_role;
320 self.havocbot_role_timeout = 0;
324 if (self.bot_strategytime < time)
326 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
327 navigation_goalrating_start();
328 havocbot_goalrating_ctf_ourstolenflag(50000);
329 havocbot_goalrating_ctf_droppedflags(50000);
330 havocbot_goalrating_items(10000, self.origin, 10000);
331 navigation_goalrating_end();
337 //if carrying flag, change role to flag carrier
338 //if our flag taken, change role to interceptor
339 //if see flag (of either team) follow it (this has many implications)
340 //(10-20 second timer) change role to defense or offense
341 //go to least recently visited area
342 void() havocbot_role_ctf_middle =
345 if (self.flagcarried)
347 dprint("changing role to carrier\n");
348 self.havocbot_role = havocbot_role_ctf_carrier;
349 self.havocbot_role_timeout = 0;
350 self.bot_cantfindflag = time + 10;
357 if (self.team == f.team)
361 if (f.cnt != FLAG_BASE && canreach(f))
363 dprint("changing role to interceptor\n");
364 self.havocbot_previous_role = self.havocbot_role;
365 self.havocbot_role = havocbot_role_ctf_interceptor;
366 self.havocbot_role_timeout = 0;
369 if (!self.havocbot_role_timeout)
370 self.havocbot_role_timeout = time + random() * 10 + 10;
371 if (time > self.havocbot_role_timeout)
375 dprint("changing role to offense\n");
376 self.havocbot_role = havocbot_role_ctf_offense;
380 dprint("changing role to defense\n");
381 self.havocbot_role = havocbot_role_ctf_defense;
383 self.havocbot_role_timeout = 0;
387 if (self.bot_strategytime < time)
389 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
390 navigation_goalrating_start();
391 havocbot_goalrating_ctf_ourstolenflag(50000);
392 havocbot_goalrating_ctf_droppedflags(30000);
393 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
394 havocbot_goalrating_items(10000, self.origin, 10000);
395 navigation_goalrating_end();
400 //if rockets < 25 || health < 100, change role to middle
401 //if carrying flag, change role to flag carrier
402 //if our flag taken, change role to interceptor
403 //(30-50 second timer) change role to middle
404 //move to nearest unclaimed defense spot
405 void() havocbot_role_ctf_defense =
408 if (self.flagcarried)
410 dprint("changing role to carrier\n");
411 self.havocbot_role = havocbot_role_ctf_carrier;
412 self.havocbot_role_timeout = 0;
413 self.bot_cantfindflag = time + 10;
420 if (self.team == f.team)
424 if (f.cnt != FLAG_BASE && canreach(f))
426 dprint("changing role to interceptor\n");
427 self.havocbot_previous_role = self.havocbot_role;
428 self.havocbot_role = havocbot_role_ctf_interceptor;
429 self.havocbot_role_timeout = 0;
432 if (!self.havocbot_role_timeout)
433 self.havocbot_role_timeout = time + random() * 20 + 30;
434 if (time > self.havocbot_role_timeout)
436 dprint("changing role to middle\n");
437 self.havocbot_role = havocbot_role_ctf_middle;
438 self.havocbot_role_timeout = 0;
441 if (self.bot_strategytime < time)
443 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
444 navigation_goalrating_start();
445 havocbot_goalrating_ctf_ourstolenflag(200000);
446 havocbot_goalrating_ctf_droppedflags(50000);
447 havocbot_goalrating_items(10000, f.origin, 10000);
448 navigation_goalrating_end();
451 // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
452 // change position occasionally
453 if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
455 self.bot_strategytime = time + random() * 45 + 15;
456 self.goalentity = world;
457 head = findchain(classname, "info_ctf_defensepoint");
460 if (time > head.count)
462 self.goalentity = head;
467 // if there are no defensepoints defined, switch to middle
468 if (self.goalentity == world)
470 dprint("changing role to middle\n");
471 self.havocbot_role = havocbot_role_ctf_middle;
472 self.havocbot_role_timeout = 0;
476 // keep anyone else from taking this spot
477 if (self.goalentity != world)
478 self.goalentity.count = time + 0.5;
483 // choose a role according to the situation
484 void() havocbot_role_dm;
485 void() havocbot_chooserole_ctf =
488 dprint("choose CTF role...\n");
489 if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
490 self.havocbot_role = havocbot_role_ctf_rogue;
495 self.havocbot_role = havocbot_role_ctf_offense;
497 self.havocbot_role = havocbot_role_ctf_middle;
499 self.havocbot_role = havocbot_role_ctf_defense;
504 //go to best items, or control points you don't own
505 void() havocbot_role_dom =
507 if (self.bot_strategytime < time)
509 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
510 navigation_goalrating_start();
511 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
512 havocbot_goalrating_items(8000, self.origin, 8000);
513 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
514 //havocbot_goalrating_waypoints(1, self.origin, 1000);
515 navigation_goalrating_end();
521 void() havocbot_role_dm =
523 if (self.bot_strategytime < time)
525 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
526 navigation_goalrating_start();
527 havocbot_goalrating_items(10000, self.origin, 10000);
528 havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
529 //havocbot_goalrating_waypoints(1, self.origin, 1000);
530 navigation_goalrating_end();
534 void() havocbot_chooserole_dm =
536 self.havocbot_role = havocbot_role_dm;
539 void() havocbot_chooserole_dom =
541 self.havocbot_role = havocbot_role_dom;
549 entity kh_worldkeylist;
550 .entity kh_worldkeynext;
551 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
554 for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
556 if(head.owner == self)
558 if(!kh_tracking_enabled)
559 if(!head.owner || head.team == self.team)
560 continue; // skip what I can't see
562 navigation_routerating(head, ratingscale_dropped, 10000);
563 else if(head.team == self.team)
564 navigation_routerating(head, ratingscale_team, 10000);
566 navigation_routerating(head, ratingscale_enemy, 10000);
570 void() havocbot_role_kh_carrier;
571 void() havocbot_role_kh_defense;
572 void() havocbot_role_kh_offense;
573 void() havocbot_role_kh_freelancer;
574 void() havocbot_role_kh_carrier =
576 if (!(self.items & IT_KEY1))
578 dprint("changing role to freelancer\n");
579 self.havocbot_role = havocbot_role_kh_freelancer;
580 self.havocbot_role_timeout = 0;
584 if (self.bot_strategytime < time)
586 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
587 navigation_goalrating_start();
589 if(kh_Key_AllOwnedByWhichTeam() == self.team)
590 havocbot_goalrating_kh(10000, 1, 1); // bring home
592 havocbot_goalrating_kh(4000, 4000, 100); // play defensively
594 havocbot_goalrating_items(10000, self.origin, 10000);
595 navigation_goalrating_end();
599 void() havocbot_role_kh_defense =
601 if (self.items & IT_KEY1)
603 dprint("changing role to carrier\n");
604 self.havocbot_role = havocbot_role_kh_carrier;
605 self.havocbot_role_timeout = 0;
609 if (!self.havocbot_role_timeout)
610 self.havocbot_role_timeout = time + random() * 10 + 20;
611 if (time > self.havocbot_role_timeout)
613 dprint("changing role to freelancer\n");
614 self.havocbot_role = havocbot_role_kh_freelancer;
615 self.havocbot_role_timeout = 0;
619 if (self.bot_strategytime < time)
621 float key_owner_team;
622 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
623 navigation_goalrating_start();
625 key_owner_team = kh_Key_AllOwnedByWhichTeam();
626 if(key_owner_team == self.team)
627 havocbot_goalrating_kh(10000, 1, 1); // defend key carriers
628 else if(key_owner_team == -1)
629 havocbot_goalrating_kh(4000, 1000, 1); // play defensively
631 havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
633 havocbot_goalrating_items(10000, self.origin, 10000);
634 navigation_goalrating_end();
638 void() havocbot_role_kh_offense =
640 if (self.items & IT_KEY1)
642 dprint("changing role to carrier\n");
643 self.havocbot_role = havocbot_role_kh_carrier;
644 self.havocbot_role_timeout = 0;
648 if (!self.havocbot_role_timeout)
649 self.havocbot_role_timeout = time + random() * 10 + 20;
650 if (time > self.havocbot_role_timeout)
652 dprint("changing role to freelancer\n");
653 self.havocbot_role = havocbot_role_kh_freelancer;
654 self.havocbot_role_timeout = 0;
658 if (self.bot_strategytime < time)
660 float key_owner_team;
662 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
663 navigation_goalrating_start();
665 key_owner_team = kh_Key_AllOwnedByWhichTeam();
666 if(key_owner_team == self.team)
667 havocbot_goalrating_kh(10000, 1, 1); // defend anyway
668 else if(key_owner_team == -1)
669 havocbot_goalrating_kh(1, 1000, 4000); // play offensively
671 havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
673 havocbot_goalrating_items(10000, self.origin, 10000);
674 navigation_goalrating_end();
678 void() havocbot_role_kh_freelancer =
680 if (self.items & IT_KEY1)
682 dprint("changing role to carrier\n");
683 self.havocbot_role = havocbot_role_kh_carrier;
684 self.havocbot_role_timeout = 0;
688 if (!self.havocbot_role_timeout)
689 self.havocbot_role_timeout = time + random() * 10 + 10;
690 if (time > self.havocbot_role_timeout)
694 dprint("changing role to offense\n");
695 self.havocbot_role = havocbot_role_kh_offense;
699 dprint("changing role to defense\n");
700 self.havocbot_role = havocbot_role_kh_defense;
702 self.havocbot_role_timeout = 0;
706 if (self.bot_strategytime < time)
708 float key_owner_team;
710 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
711 navigation_goalrating_start();
713 key_owner_team = kh_Key_AllOwnedByWhichTeam();
714 if(key_owner_team == self.team)
715 havocbot_goalrating_kh(10000, 1, 1); // defend anyway
716 else if(key_owner_team == -1)
717 havocbot_goalrating_kh(1000, 4000, 1000); // prefer dropped keys
719 havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
721 havocbot_goalrating_items(10000, self.origin, 10000);
722 navigation_goalrating_end();
730 void() havocbot_chooserole_kh =
735 self.havocbot_role = havocbot_role_kh_offense;
737 self.havocbot_role = havocbot_role_kh_defense;
739 self.havocbot_role = havocbot_role_kh_freelancer;
742 void() havocbot_chooserole =
744 dprint("choose a role...\n");
745 navigation_routetogoal(world);
746 self.bot_strategytime = -1;
748 havocbot_chooserole_ctf();
749 else if (g_domination)
750 havocbot_chooserole_dom();
752 havocbot_chooserole_kh();
753 else // assume anything else is deathmatch
754 havocbot_chooserole_dm();