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;
550 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
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);
571 void() havocbot_role_kh_carrier;
572 void() havocbot_role_kh_defense;
573 void() havocbot_role_kh_offense;
574 void() havocbot_role_kh_freelancer;
575 void() havocbot_role_kh_carrier =
577 if (!(self.items & IT_KEY1))
579 dprint("changing role to freelancer\n");
580 self.havocbot_role = havocbot_role_kh_freelancer;
581 self.havocbot_role_timeout = 0;
585 if (self.bot_strategytime < time)
587 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
588 navigation_goalrating_start();
590 if(kh_Key_AllOwnedByWhichTeam() == self.team)
591 havocbot_goalrating_kh(10000, 1, 1); // bring home
593 havocbot_goalrating_kh(4000, 4000, 100); // play defensively
595 havocbot_goalrating_items(10000, self.origin, 10000);
596 navigation_goalrating_end();
600 void() havocbot_role_kh_defense =
602 if (self.items & IT_KEY1)
604 dprint("changing role to carrier\n");
605 self.havocbot_role = havocbot_role_kh_carrier;
606 self.havocbot_role_timeout = 0;
610 if (!self.havocbot_role_timeout)
611 self.havocbot_role_timeout = time + random() * 10 + 20;
612 if (time > self.havocbot_role_timeout)
614 dprint("changing role to freelancer\n");
615 self.havocbot_role = havocbot_role_kh_freelancer;
616 self.havocbot_role_timeout = 0;
620 if (self.bot_strategytime < time)
622 float key_owner_team;
623 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
624 navigation_goalrating_start();
626 key_owner_team = kh_Key_AllOwnedByWhichTeam();
627 if(key_owner_team == self.team)
628 havocbot_goalrating_kh(10000, 1, 1); // defend key carriers
629 else if(key_owner_team == -1)
630 havocbot_goalrating_kh(4000, 1000, 1); // play defensively
632 havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
634 havocbot_goalrating_items(10000, self.origin, 10000);
635 navigation_goalrating_end();
639 void() havocbot_role_kh_offense =
641 if (self.items & IT_KEY1)
643 dprint("changing role to carrier\n");
644 self.havocbot_role = havocbot_role_kh_carrier;
645 self.havocbot_role_timeout = 0;
649 if (!self.havocbot_role_timeout)
650 self.havocbot_role_timeout = time + random() * 10 + 20;
651 if (time > self.havocbot_role_timeout)
653 dprint("changing role to freelancer\n");
654 self.havocbot_role = havocbot_role_kh_freelancer;
655 self.havocbot_role_timeout = 0;
659 if (self.bot_strategytime < time)
661 float key_owner_team;
663 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
664 navigation_goalrating_start();
666 key_owner_team = kh_Key_AllOwnedByWhichTeam();
667 if(key_owner_team == self.team)
668 havocbot_goalrating_kh(10000, 1, 1); // defend anyway
669 else if(key_owner_team == -1)
670 havocbot_goalrating_kh(1, 1000, 4000); // play offensively
672 havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
674 havocbot_goalrating_items(10000, self.origin, 10000);
675 navigation_goalrating_end();
679 void() havocbot_role_kh_freelancer =
681 if (self.items & IT_KEY1)
683 dprint("changing role to carrier\n");
684 self.havocbot_role = havocbot_role_kh_carrier;
685 self.havocbot_role_timeout = 0;
689 if (!self.havocbot_role_timeout)
690 self.havocbot_role_timeout = time + random() * 10 + 10;
691 if (time > self.havocbot_role_timeout)
695 dprint("changing role to offense\n");
696 self.havocbot_role = havocbot_role_kh_offense;
700 dprint("changing role to defense\n");
701 self.havocbot_role = havocbot_role_kh_defense;
703 self.havocbot_role_timeout = 0;
707 if (self.bot_strategytime < time)
709 float key_owner_team;
711 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
712 navigation_goalrating_start();
714 key_owner_team = kh_Key_AllOwnedByWhichTeam();
715 if(key_owner_team == self.team)
716 havocbot_goalrating_kh(10000, 1, 1); // defend anyway
717 else if(key_owner_team == -1)
718 havocbot_goalrating_kh(1000, 4000, 1000); // prefer dropped keys
720 havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
722 havocbot_goalrating_items(10000, self.origin, 10000);
723 navigation_goalrating_end();
731 void() havocbot_chooserole_kh =
736 self.havocbot_role = havocbot_role_kh_offense;
738 self.havocbot_role = havocbot_role_kh_defense;
740 self.havocbot_role = havocbot_role_kh_freelancer;
743 void() havocbot_chooserole =
745 dprint("choose a role...\n");
746 navigation_routetogoal(world);
747 self.bot_strategytime = -1;
749 havocbot_chooserole_ctf();
750 else if (g_domination)
751 havocbot_chooserole_dom();
753 havocbot_chooserole_kh();
754 else // assume anything else is deathmatch
755 havocbot_chooserole_dm();