]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/havocbot_roles.qc
fix bug with keyhunt key list using .enemy field, now uses
[divverent/nexuiz.git] / data / qcsrc / server / havocbot_roles.qc
1
2 .float havocbot_role_timeout;
3 .void() havocbot_previous_role;
4 .float bot_strategytime;
5 .void() havocbot_role;
6 float bot_ignore_bots;
7
8 float(entity e) canreach =
9 {
10         return vlen(self.origin - e.origin) < 1500;
11 }
12
13 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items =
14 {
15         local entity head;
16         local float t;
17         ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
18         head = findchainfloat(bot_pickup, TRUE);
19         while (head)
20         {
21                 if (head.solid) // must be possible to pick up (respawning items don't count)
22                 if (vlen(head.origin - org) < sradius)
23                 {
24                         // debugging
25                         //if (!head.bot_pickupevalfunc || head.model == "")
26                         //      eprint(head);
27                         // get the value of the item
28                         t = head.bot_pickupevalfunc(self, head);
29                         if (t > 0)
30                                 navigation_routerating(head, t * ratingscale, 2000);
31                 }
32                 head = head.chain;
33         }
34 };
35
36 void(float ratingscale, vector org, float sradius) havocbot_goalrating_controlpoints =
37 {
38         local entity head;
39         head = findchain(classname, "dom_controlpoint");
40         while (head)
41         {
42                 if (vlen(head.origin - org) < sradius)
43                 {
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);
50                 }
51                 head = head.chain;
52         }
53 };
54
55 /*
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 =
60 {
61         local entity head;
62         head = findchain(classname, "waypoint");
63         while (head)
64         {
65                 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
66                         navigation_routerating(head, ratingscale, 2000);
67                 head = head.chain;
68         }
69 };
70 */
71
72 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers =
73 {
74         local entity head;
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));
79         //dprint("\n");
80
81         FOR_EACH_PLAYER(head)
82         {
83                 if (self != head)
84                 if (head.health > 0)
85                 if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
86                 if (vlen(head.origin - org) < sradius)
87                 {
88                         t = 100 / (head.health + head.armorvalue);
89                         if (t > 0)
90                         {
91                                 //dprint("found: "); dprint(head.netname); dprint("\n");
92                                 navigation_routerating(head, t * ratingscale, 500);
93                         }
94                 }
95         }
96 };
97
98
99 void() havocbot_role_ctf_middle;
100 void() havocbot_role_ctf_defense;
101 void() havocbot_role_ctf_offense;
102 void() havocbot_role_ctf_interceptor;
103
104 void(float ratingscale, vector org, float sradius) havocbot_goalrating_ctf_carrieritems =
105 {
106         local entity head;
107         local float t;
108         head = findchainfloat(bot_pickup, TRUE);
109         while (head)
110         {
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)
115                 {
116                         // debugging
117                         //if (!head.bot_pickupevalfunc || head.model == "")
118                         //      eprint(head);
119                         // get the value of the item
120                         t = head.bot_pickupevalfunc(self, head) * 0.0001;
121                         if (t > 0)
122                                 navigation_routerating(head, t * ratingscale, 500);
123                 }
124                 head = head.chain;
125         }
126 };
127
128 entity flaglist;
129 void(float ratingscale) havocbot_goalrating_ctf_ourflag =
130 {
131         local entity head;
132         head = flaglist;
133         while (head)
134         {
135                 if (self.team == head.team)
136                         break;
137                 head = head.enemy;
138         }
139         if (head)
140                 navigation_routerating(head, ratingscale, 10000);
141 };
142
143 void(float ratingscale) havocbot_goalrating_ctf_enemyflag =
144 {
145         local entity head;
146         head = flaglist;
147         while (head)
148         {
149                 if (self.team != head.team)
150                         break;
151                 head = head.enemy;
152         }
153         if (head)
154                 navigation_routerating(head, ratingscale, 10000);
155 };
156
157 void(float ratingscale) havocbot_goalrating_ctf_enemybase =
158 {
159         // div0: needs a change in the CTF code
160 };
161
162 void(float ratingscale) havocbot_goalrating_ctf_ourstolenflag =
163 {
164         local entity head;
165         head = flaglist;
166         while (head)
167         {
168                 if (self.team == head.team)
169                         break;
170                 head = head.enemy;
171         }
172         if (head)
173         if (head.cnt != FLAG_BASE)
174                 navigation_routerating(head, ratingscale, 10000);
175 };
176
177 void(float ratingscale) havocbot_goalrating_ctf_droppedflags =
178 {
179         local entity head;
180         head = flaglist;
181         while (head)
182         {
183                 if (head.cnt != FLAG_BASE) // flag is carried or out in the field
184                         navigation_routerating(head, ratingscale, 10000);
185                 head = head.enemy;
186         }
187 };
188
189 // CTF: (always teamplay)
190
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 =
194 {
195         if (self.bot_strategytime < time)
196         {
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();
203         }
204 }
205
206 //role flag carrier:
207 //pick up armor and health
208 //go to our flag spot
209 .float bot_cantfindflag;
210 void() havocbot_role_ctf_carrier =
211 {
212         if (self.flagcarried == world)
213         {
214                 dprint("changing role to middle\n");
215                 self.havocbot_role = havocbot_role_ctf_middle;
216                 self.havocbot_role_timeout = 0;
217                 return;
218         }
219         if (self.bot_strategytime < time)
220         {
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)
227                 {
228                         // can't navigate to our own flag :(
229                         Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
230                 }
231                 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
232                 navigation_goalrating_end();
233         }
234 };
235
236 //role offense:
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
242 //go to enemy flag
243 void() havocbot_role_ctf_offense =
244 {
245         local entity f;
246         if (self.flagcarried)
247         {
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;
252                 return;
253         }
254         // check our flag
255         f = flaglist;
256         while (f)
257         {
258                 if (self.team == f.team)
259                         break;
260                 f = f.enemy;
261         }
262         if (f.cnt != FLAG_BASE && canreach(f))
263         {
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;
268                 return;
269         }
270         if (!self.havocbot_role_timeout)
271                 self.havocbot_role_timeout = time + random() * 30 + 60;
272         if (time > self.havocbot_role_timeout)
273         {
274                 dprint("changing role to middle\n");
275                 self.havocbot_role = havocbot_role_ctf_middle;
276                 self.havocbot_role_timeout = 0;
277                 return;
278         }
279         if (self.bot_strategytime < time)
280         {
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();
288         }
289 };
290
291 //role interceptor (temporary role):
292 //pick up items
293 //if carrying flag, change role to flag carrier
294 //if our flag is back, change role to previous role
295 //follow our flag
296 //go to least recently visited area
297 void() havocbot_role_ctf_interceptor =
298 {
299         local entity f;
300         if (self.flagcarried)
301         {
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;
306                 return;
307         }
308         // check our flag
309         f = flaglist;
310         while (f)
311         {
312                 if (self.team == f.team)
313                         break;
314                 f = f.enemy;
315         }
316         if (f.cnt == FLAG_BASE)
317         {
318                 dprint("changing role back\n");
319                 self.havocbot_role = self.havocbot_previous_role;
320                 self.havocbot_role_timeout = 0;
321                 return;
322         }
323
324         if (self.bot_strategytime < time)
325         {
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();
332         }
333 };
334
335 //role middle:
336 //pick up items
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 =
343 {
344         local entity f;
345         if (self.flagcarried)
346         {
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;
351                 return;
352         }
353         // check our flag
354         f = flaglist;
355         while (f)
356         {
357                 if (self.team == f.team)
358                         break;
359                 f = f.enemy;
360         }
361         if (f.cnt != FLAG_BASE && canreach(f))
362         {
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;
367                 return;
368         }
369         if (!self.havocbot_role_timeout)
370                 self.havocbot_role_timeout = time + random() * 10 + 10;
371         if (time > self.havocbot_role_timeout)
372         {
373                 if (random() < 0.5)
374                 {
375                         dprint("changing role to offense\n");
376                         self.havocbot_role = havocbot_role_ctf_offense;
377                 }
378                 else
379                 {
380                         dprint("changing role to defense\n");
381                         self.havocbot_role = havocbot_role_ctf_defense;
382                 }
383                 self.havocbot_role_timeout = 0;
384                 return;
385         }
386
387         if (self.bot_strategytime < time)
388         {
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();
396         }
397 };
398
399 //role defense:
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 =
406 {
407         local entity f;
408         if (self.flagcarried)
409         {
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;
414                 return;
415         }
416         // check our flag
417         f = flaglist;
418         while (f)
419         {
420                 if (self.team == f.team)
421                         break;
422                 f = f.enemy;
423         }
424         if (f.cnt != FLAG_BASE && canreach(f))
425         {
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;
430                 return;
431         }
432         if (!self.havocbot_role_timeout)
433                 self.havocbot_role_timeout = time + random() * 20 + 30;
434         if (time > self.havocbot_role_timeout)
435         {
436                 dprint("changing role to middle\n");
437                 self.havocbot_role = havocbot_role_ctf_middle;
438                 self.havocbot_role_timeout = 0;
439                 return;
440         }
441         if (self.bot_strategytime < time)
442         {
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();
449         }
450         /*
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")
454         {
455                 self.bot_strategytime = time + random() * 45 + 15;
456                 self.goalentity = world;
457                 head = findchain(classname, "info_ctf_defensepoint");
458                 while (head)
459                 {
460                         if (time > head.count)
461                         {
462                                 self.goalentity = head;
463                                 head.chain = world;
464                         }
465                         head = head.chain;
466                 }
467                 // if there are no defensepoints defined, switch to middle
468                 if (self.goalentity == world)
469                 {
470                         dprint("changing role to middle\n");
471                         self.havocbot_role = havocbot_role_ctf_middle;
472                         self.havocbot_role_timeout = 0;
473                         return;
474                 }
475         }
476         // keep anyone else from taking this spot
477         if (self.goalentity != world)
478                 self.goalentity.count = time + 0.5;
479         */
480 };
481
482 // CTF:
483 // choose a role according to the situation
484 void() havocbot_role_dm;
485 void() havocbot_chooserole_ctf =
486 {
487         local float r;
488         dprint("choose CTF role...\n");
489         if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
490                 self.havocbot_role = havocbot_role_ctf_rogue;
491         else
492         {
493                 r = random() * 3;
494                 if (r < 1)
495                         self.havocbot_role = havocbot_role_ctf_offense;
496                 else if (r < 2)
497                         self.havocbot_role = havocbot_role_ctf_middle;
498                 else
499                         self.havocbot_role = havocbot_role_ctf_defense;
500         }
501 };
502
503 //DOM:
504 //go to best items, or control points you don't own
505 void() havocbot_role_dom =
506 {
507         if (self.bot_strategytime < time)
508         {
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();
516         }
517 };
518
519 //DM:
520 //go to best items
521 void() havocbot_role_dm =
522 {
523         if (self.bot_strategytime < time)
524         {
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();
531         }
532 };
533
534 void() havocbot_chooserole_dm =
535 {
536         self.havocbot_role = havocbot_role_dm;
537 };
538
539 void() havocbot_chooserole_dom =
540 {
541         self.havocbot_role = havocbot_role_dom;
542 };
543
544
545
546
547
548
549 entity kh_worldkeylist;
550 .entity kh_worldkeynext;
551 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
552 {
553         local entity head;
554         for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
555         {
556                 if(head.owner == self)
557                         continue;
558                 if(!kh_tracking_enabled)
559                         if(!head.owner || head.team == self.team)
560                                 continue; // skip what I can't see
561                 if(!head.owner)
562                         navigation_routerating(head, ratingscale_dropped, 10000);
563                 else if(head.team == self.team)
564                         navigation_routerating(head, ratingscale_team, 10000);
565                 else
566                         navigation_routerating(head, ratingscale_enemy, 10000);
567         }
568 };
569
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 =
575 {
576         if (!(self.items & IT_KEY1))
577         {
578                 dprint("changing role to freelancer\n");
579                 self.havocbot_role = havocbot_role_kh_freelancer;
580                 self.havocbot_role_timeout = 0;
581                 return;
582         }
583
584         if (self.bot_strategytime < time)
585         {
586                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
587                 navigation_goalrating_start();
588
589                 if(kh_Key_AllOwnedByWhichTeam() == self.team)
590                         havocbot_goalrating_kh(10000, 1, 1); // bring home
591                 else
592                         havocbot_goalrating_kh(4000, 4000, 100); // play defensively
593
594                 havocbot_goalrating_items(10000, self.origin, 10000);
595                 navigation_goalrating_end();
596         }
597 }
598
599 void() havocbot_role_kh_defense =
600 {
601         if (self.items & IT_KEY1)
602         {
603                 dprint("changing role to carrier\n");
604                 self.havocbot_role = havocbot_role_kh_carrier;
605                 self.havocbot_role_timeout = 0;
606                 return;
607         }
608
609         if (!self.havocbot_role_timeout)
610                 self.havocbot_role_timeout = time + random() * 10 + 20;
611         if (time > self.havocbot_role_timeout)
612         {
613                 dprint("changing role to freelancer\n");
614                 self.havocbot_role = havocbot_role_kh_freelancer;
615                 self.havocbot_role_timeout = 0;
616                 return;
617         }
618
619         if (self.bot_strategytime < time)
620         {
621                 float key_owner_team;
622                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
623                 navigation_goalrating_start();
624
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
630                 else
631                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
632
633                 havocbot_goalrating_items(10000, self.origin, 10000);
634                 navigation_goalrating_end();
635         }
636 };
637
638 void() havocbot_role_kh_offense =
639 {
640         if (self.items & IT_KEY1)
641         {
642                 dprint("changing role to carrier\n");
643                 self.havocbot_role = havocbot_role_kh_carrier;
644                 self.havocbot_role_timeout = 0;
645                 return;
646         }
647
648         if (!self.havocbot_role_timeout)
649                 self.havocbot_role_timeout = time + random() * 10 + 20;
650         if (time > self.havocbot_role_timeout)
651         {
652                 dprint("changing role to freelancer\n");
653                 self.havocbot_role = havocbot_role_kh_freelancer;
654                 self.havocbot_role_timeout = 0;
655                 return;
656         }
657
658         if (self.bot_strategytime < time)
659         {
660                 float key_owner_team;
661
662                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
663                 navigation_goalrating_start();
664
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
670                 else
671                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
672
673                 havocbot_goalrating_items(10000, self.origin, 10000);
674                 navigation_goalrating_end();
675         }
676 };
677
678 void() havocbot_role_kh_freelancer =
679 {
680         if (self.items & IT_KEY1)
681         {
682                 dprint("changing role to carrier\n");
683                 self.havocbot_role = havocbot_role_kh_carrier;
684                 self.havocbot_role_timeout = 0;
685                 return;
686         }
687
688         if (!self.havocbot_role_timeout)
689                 self.havocbot_role_timeout = time + random() * 10 + 10;
690         if (time > self.havocbot_role_timeout)
691         {
692                 if (random() < 0.5)
693                 {
694                         dprint("changing role to offense\n");
695                         self.havocbot_role = havocbot_role_kh_offense;
696                 }
697                 else
698                 {
699                         dprint("changing role to defense\n");
700                         self.havocbot_role = havocbot_role_kh_defense;
701                 }
702                 self.havocbot_role_timeout = 0;
703                 return;
704         }
705
706         if (self.bot_strategytime < time)
707         {
708                 float key_owner_team;
709
710                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
711                 navigation_goalrating_start();
712
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
718                 else
719                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
720
721                 havocbot_goalrating_items(10000, self.origin, 10000);
722                 navigation_goalrating_end();
723         }
724 };
725
726
727
728
729
730 void() havocbot_chooserole_kh =
731 {
732         local float r;
733         r = random() * 3;
734         if (r < 1)
735                 self.havocbot_role = havocbot_role_kh_offense;
736         else if (r < 2)
737                 self.havocbot_role = havocbot_role_kh_defense;
738         else
739                 self.havocbot_role = havocbot_role_kh_freelancer;
740 };
741
742 void() havocbot_chooserole =
743 {
744         dprint("choose a role...\n");
745         navigation_routetogoal(world);
746         self.bot_strategytime = -1;
747         if (g_ctf)
748                 havocbot_chooserole_ctf();
749         else if (g_domination)
750                 havocbot_chooserole_dom();
751         else if (g_keyhunt)
752                 havocbot_chooserole_kh();
753         else // assume anything else is deathmatch
754                 havocbot_chooserole_dm();
755 };
756