2 .float havocbot_role_timeout;
3 .void() havocbot_previous_role;
4 .float bot_strategytime;
8 float canreach(entity e)
10 return vlen(self.origin - e.origin) < 1500;
13 void havocbot_goalrating_items(float ratingscale, vector org, float sradius)
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 havocbot_goalrating_controlpoints(float ratingscale, vector org, float sradius)
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 havocbot_goalrating_waypoints(float ratingscale, vector org, float sradius)
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 havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
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 havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
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);
128 entity ctf_worldflaglist;
129 .entity ctf_worldflagnext;
130 void havocbot_goalrating_ctf_ourflag(float ratingscale)
133 head = ctf_worldflaglist;
136 if (self.team == head.team)
138 head = head.ctf_worldflagnext;
141 navigation_routerating(head, ratingscale, 10000);
144 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
147 head = ctf_worldflaglist;
150 if (self.team != head.team)
152 head = head.ctf_worldflagnext;
155 navigation_routerating(head, ratingscale, 10000);
158 void havocbot_goalrating_ctf_enemybase(float ratingscale)
160 // div0: needs a change in the CTF code
163 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
166 head = ctf_worldflaglist;
169 if (self.team == head.team)
171 head = head.ctf_worldflagnext;
174 if (head.cnt != FLAG_BASE)
175 navigation_routerating(head, ratingscale, 10000);
178 void havocbot_goalrating_ctf_droppedflags(float ratingscale)
181 head = ctf_worldflaglist;
184 if (head.cnt != FLAG_BASE) // flag is carried or out in the field
185 navigation_routerating(head, ratingscale, 10000);
186 head = head.ctf_worldflagnext;
190 // CTF: (always teamplay)
192 //role rogue: (is this used?)
193 //pick up items and dropped flags (with big rating boost to dropped flags)
194 void havocbot_role_ctf_rogue()
196 if (self.bot_strategytime < time)
198 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
199 navigation_goalrating_start();
200 havocbot_goalrating_ctf_droppedflags(5000);
201 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
202 havocbot_goalrating_items(10000, self.origin, 10000);
203 navigation_goalrating_end();
208 //pick up armor and health
209 //go to our flag spot
210 .float bot_cantfindflag;
211 void havocbot_role_ctf_carrier()
213 if (self.flagcarried == world)
215 dprint("changing role to middle\n");
216 self.havocbot_role = havocbot_role_ctf_middle;
217 self.havocbot_role_timeout = 0;
220 if (self.bot_strategytime < time)
222 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
223 navigation_goalrating_start();
224 havocbot_goalrating_ctf_ourflag(50000);
225 if (navigation_bestgoal)
226 self.bot_cantfindflag = time + 10;
227 else if (time > self.bot_cantfindflag)
229 // can't navigate to our own flag :(
230 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
232 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
233 navigation_goalrating_end();
238 //pick up armor and health
239 //if rockets < 25 || health < 100, change role to middle
240 //if carrying flag, change role to flag carrier
241 //if our flag taken, change role to interceptor
242 //(60-90 second timer) change role to middle
244 void havocbot_role_ctf_offense()
247 if (self.flagcarried)
249 dprint("changing role to carrier\n");
250 self.havocbot_role = havocbot_role_ctf_carrier;
251 self.havocbot_role_timeout = 0;
252 self.bot_cantfindflag = time + 10;
256 f = ctf_worldflaglist;
259 if (self.team == f.team)
261 f = f.ctf_worldflagnext;
263 if (f.cnt != FLAG_BASE && canreach(f))
265 dprint("changing role to interceptor\n");
266 self.havocbot_previous_role = self.havocbot_role;
267 self.havocbot_role = havocbot_role_ctf_interceptor;
268 self.havocbot_role_timeout = 0;
271 if (!self.havocbot_role_timeout)
272 self.havocbot_role_timeout = time + random() * 30 + 60;
273 if (time > self.havocbot_role_timeout)
275 dprint("changing role to middle\n");
276 self.havocbot_role = havocbot_role_ctf_middle;
277 self.havocbot_role_timeout = 0;
280 if (self.bot_strategytime < time)
282 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
283 navigation_goalrating_start();
284 havocbot_goalrating_ctf_ourstolenflag(50000);
285 havocbot_goalrating_ctf_enemyflag(30000);
286 havocbot_goalrating_ctf_enemybase(20000);
287 havocbot_goalrating_items(10000, self.origin, 10000);
288 navigation_goalrating_end();
292 //role interceptor (temporary role):
294 //if carrying flag, change role to flag carrier
295 //if our flag is back, change role to previous role
297 //go to least recently visited area
298 void havocbot_role_ctf_interceptor()
301 if (self.flagcarried)
303 dprint("changing role to carrier\n");
304 self.havocbot_role = havocbot_role_ctf_carrier;
305 self.havocbot_role_timeout = 0;
306 self.bot_cantfindflag = time + 10;
310 f = ctf_worldflaglist;
313 if (self.team == f.team)
315 f = f.ctf_worldflagnext;
317 if (f.cnt == FLAG_BASE)
319 dprint("changing role back\n");
320 self.havocbot_role = self.havocbot_previous_role;
321 self.havocbot_role_timeout = 0;
325 if (self.bot_strategytime < time)
327 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
328 navigation_goalrating_start();
329 havocbot_goalrating_ctf_ourstolenflag(50000);
330 havocbot_goalrating_ctf_droppedflags(50000);
331 havocbot_goalrating_items(10000, self.origin, 10000);
332 navigation_goalrating_end();
338 //if carrying flag, change role to flag carrier
339 //if our flag taken, change role to interceptor
340 //if see flag (of either team) follow it (this has many implications)
341 //(10-20 second timer) change role to defense or offense
342 //go to least recently visited area
343 void havocbot_role_ctf_middle()
346 if (self.flagcarried)
348 dprint("changing role to carrier\n");
349 self.havocbot_role = havocbot_role_ctf_carrier;
350 self.havocbot_role_timeout = 0;
351 self.bot_cantfindflag = time + 10;
355 f = ctf_worldflaglist;
358 if (self.team == f.team)
360 f = f.ctf_worldflagnext;
362 if (f.cnt != FLAG_BASE && canreach(f))
364 dprint("changing role to interceptor\n");
365 self.havocbot_previous_role = self.havocbot_role;
366 self.havocbot_role = havocbot_role_ctf_interceptor;
367 self.havocbot_role_timeout = 0;
370 if (!self.havocbot_role_timeout)
371 self.havocbot_role_timeout = time + random() * 10 + 10;
372 if (time > self.havocbot_role_timeout)
376 dprint("changing role to offense\n");
377 self.havocbot_role = havocbot_role_ctf_offense;
381 dprint("changing role to defense\n");
382 self.havocbot_role = havocbot_role_ctf_defense;
384 self.havocbot_role_timeout = 0;
388 if (self.bot_strategytime < time)
390 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
391 navigation_goalrating_start();
392 havocbot_goalrating_ctf_ourstolenflag(50000);
393 havocbot_goalrating_ctf_droppedflags(30000);
394 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
395 havocbot_goalrating_items(10000, self.origin, 10000);
396 navigation_goalrating_end();
401 //if rockets < 25 || health < 100, change role to middle
402 //if carrying flag, change role to flag carrier
403 //if our flag taken, change role to interceptor
404 //(30-50 second timer) change role to middle
405 //move to nearest unclaimed defense spot
406 void havocbot_role_ctf_defense()
409 if (self.flagcarried)
411 dprint("changing role to carrier\n");
412 self.havocbot_role = havocbot_role_ctf_carrier;
413 self.havocbot_role_timeout = 0;
414 self.bot_cantfindflag = time + 10;
418 f = ctf_worldflaglist;
421 if (self.team == f.team)
423 f = f.ctf_worldflagnext;
425 if (f.cnt != FLAG_BASE && canreach(f))
427 dprint("changing role to interceptor\n");
428 self.havocbot_previous_role = self.havocbot_role;
429 self.havocbot_role = havocbot_role_ctf_interceptor;
430 self.havocbot_role_timeout = 0;
433 if (!self.havocbot_role_timeout)
434 self.havocbot_role_timeout = time + random() * 20 + 30;
435 if (time > self.havocbot_role_timeout)
437 dprint("changing role to middle\n");
438 self.havocbot_role = havocbot_role_ctf_middle;
439 self.havocbot_role_timeout = 0;
442 if (self.bot_strategytime < time)
444 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
445 navigation_goalrating_start();
446 havocbot_goalrating_ctf_ourstolenflag(200000);
447 havocbot_goalrating_ctf_droppedflags(50000);
448 havocbot_goalrating_items(10000, f.origin, 10000);
449 navigation_goalrating_end();
452 // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
453 // change position occasionally
454 if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
456 self.bot_strategytime = time + random() * 45 + 15;
457 self.goalentity = world;
458 head = findchain(classname, "info_ctf_defensepoint");
461 if (time > head.count)
463 self.goalentity = head;
468 // if there are no defensepoints defined, switch to middle
469 if (self.goalentity == world)
471 dprint("changing role to middle\n");
472 self.havocbot_role = havocbot_role_ctf_middle;
473 self.havocbot_role_timeout = 0;
477 // keep anyone else from taking this spot
478 if (self.goalentity != world)
479 self.goalentity.count = time + 0.5;
484 // choose a role according to the situation
485 void() havocbot_role_dm;
486 void havocbot_chooserole_ctf()
489 dprint("choose CTF role...\n");
490 if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
491 self.havocbot_role = havocbot_role_ctf_rogue;
496 self.havocbot_role = havocbot_role_ctf_offense;
498 self.havocbot_role = havocbot_role_ctf_middle;
500 self.havocbot_role = havocbot_role_ctf_defense;
505 //go to best items, or control points you don't own
506 void havocbot_role_dom()
508 if (self.bot_strategytime < time)
510 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
511 navigation_goalrating_start();
512 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
513 havocbot_goalrating_items(8000, self.origin, 8000);
514 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
515 //havocbot_goalrating_waypoints(1, self.origin, 1000);
516 navigation_goalrating_end();
522 void havocbot_role_dm()
524 if (self.bot_strategytime < time)
526 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
527 navigation_goalrating_start();
528 havocbot_goalrating_items(10000, self.origin, 10000);
529 havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
530 //havocbot_goalrating_waypoints(1, self.origin, 1000);
531 navigation_goalrating_end();
535 void havocbot_chooserole_dm()
537 self.havocbot_role = havocbot_role_dm;
540 void havocbot_chooserole_dom()
542 self.havocbot_role = havocbot_role_dom;
550 entity kh_worldkeylist;
551 .entity kh_worldkeynext;
552 void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
555 for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
557 if(head.owner == self)
559 if(!kh_tracking_enabled)
561 // if it's carried by our team we know about it
562 // otherwise we have to see it to know about it
563 if(!head.owner || head.team != self.team)
565 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
566 if (trace_fraction < 1 && trace_ent != head)
567 continue; // skip what I can't see
571 navigation_routerating(head, ratingscale_dropped, 100000);
572 else if(head.team == self.team)
573 navigation_routerating(head, ratingscale_team, 100000);
575 navigation_routerating(head, ratingscale_enemy, 100000);
579 void() havocbot_role_kh_carrier;
580 void() havocbot_role_kh_defense;
581 void() havocbot_role_kh_offense;
582 void() havocbot_role_kh_freelancer;
583 void havocbot_role_kh_carrier()
585 if (!(self.items & IT_KEY1))
587 dprint("changing role to freelancer\n");
588 self.havocbot_role = havocbot_role_kh_freelancer;
589 self.havocbot_role_timeout = 0;
593 if (self.bot_strategytime < time)
595 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
596 navigation_goalrating_start();
598 if(kh_Key_AllOwnedByWhichTeam() == self.team)
599 havocbot_goalrating_kh(100000, 1, 1); // bring home
601 havocbot_goalrating_kh(40000, 40000, 1000); // play defensively
603 havocbot_goalrating_items(10000, self.origin, 10000);
604 navigation_goalrating_end();
608 void havocbot_role_kh_defense()
610 if (self.items & IT_KEY1)
612 dprint("changing role to carrier\n");
613 self.havocbot_role = havocbot_role_kh_carrier;
614 self.havocbot_role_timeout = 0;
618 if (!self.havocbot_role_timeout)
619 self.havocbot_role_timeout = time + random() * 10 + 20;
620 if (time > self.havocbot_role_timeout)
622 dprint("changing role to freelancer\n");
623 self.havocbot_role = havocbot_role_kh_freelancer;
624 self.havocbot_role_timeout = 0;
628 if (self.bot_strategytime < time)
630 float key_owner_team;
631 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
632 navigation_goalrating_start();
634 key_owner_team = kh_Key_AllOwnedByWhichTeam();
635 if(key_owner_team == self.team)
636 havocbot_goalrating_kh(100000, 1, 1); // defend key carriers
637 else if(key_owner_team == -1)
638 havocbot_goalrating_kh(40000, 10000, 1); // play defensively
640 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
642 havocbot_goalrating_items(10000, self.origin, 10000);
643 navigation_goalrating_end();
647 void havocbot_role_kh_offense()
649 if (self.items & IT_KEY1)
651 dprint("changing role to carrier\n");
652 self.havocbot_role = havocbot_role_kh_carrier;
653 self.havocbot_role_timeout = 0;
657 if (!self.havocbot_role_timeout)
658 self.havocbot_role_timeout = time + random() * 10 + 20;
659 if (time > self.havocbot_role_timeout)
661 dprint("changing role to freelancer\n");
662 self.havocbot_role = havocbot_role_kh_freelancer;
663 self.havocbot_role_timeout = 0;
667 if (self.bot_strategytime < time)
669 float key_owner_team;
671 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
672 navigation_goalrating_start();
674 key_owner_team = kh_Key_AllOwnedByWhichTeam();
675 if(key_owner_team == self.team)
676 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
677 else if(key_owner_team == -1)
678 havocbot_goalrating_kh(1, 10000, 40000); // play offensively
680 havocbot_goalrating_kh(1, 1, 100000); // ATTACK! EMERGENCY!
682 havocbot_goalrating_items(10000, self.origin, 10000);
683 navigation_goalrating_end();
687 void havocbot_role_kh_freelancer()
689 if (self.items & IT_KEY1)
691 dprint("changing role to carrier\n");
692 self.havocbot_role = havocbot_role_kh_carrier;
693 self.havocbot_role_timeout = 0;
697 if (!self.havocbot_role_timeout)
698 self.havocbot_role_timeout = time + random() * 10 + 10;
699 if (time > self.havocbot_role_timeout)
703 dprint("changing role to offense\n");
704 self.havocbot_role = havocbot_role_kh_offense;
708 dprint("changing role to defense\n");
709 self.havocbot_role = havocbot_role_kh_defense;
711 self.havocbot_role_timeout = 0;
715 if (self.bot_strategytime < time)
717 float key_owner_team;
719 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
720 navigation_goalrating_start();
722 key_owner_team = kh_Key_AllOwnedByWhichTeam();
723 if(key_owner_team == self.team)
724 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
725 else if(key_owner_team == -1)
726 havocbot_goalrating_kh(10000, 40000, 10000); // prefer dropped keys
728 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
730 havocbot_goalrating_items(10000, self.origin, 10000);
731 navigation_goalrating_end();
739 void havocbot_chooserole_kh()
744 self.havocbot_role = havocbot_role_kh_offense;
746 self.havocbot_role = havocbot_role_kh_defense;
748 self.havocbot_role = havocbot_role_kh_freelancer;
751 void havocbot_chooserole()
753 dprint("choose a role...\n");
754 navigation_routetogoal(world);
755 self.bot_strategytime = -1;
757 havocbot_chooserole_ctf();
758 else if (g_domination)
759 havocbot_chooserole_dom();
761 havocbot_chooserole_kh();
762 else // assume anything else is deathmatch
763 havocbot_chooserole_dm();