]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/havocbot_roles.qc
Added a clientside QuakeC base by Dresk and myself. Included an example of a networke...
[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);
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);
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);
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);
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);
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);
123                 }
124                 head = head.chain;
125         }
126 };
127
128 void(float ratingscale) havocbot_goalrating_ctf_ourflag =
129 {
130         local entity head;
131         if (self.team == COLOR_TEAM1) // red
132                 head = find(world, classname, "item_flag_team1"); // red flag
133         else // blue
134                 head = find(world, classname, "item_flag_team2"); // blue flag
135         navigation_routerating(head, ratingscale);
136 };
137
138 void(float ratingscale) havocbot_goalrating_ctf_enemyflag =
139 {
140         local entity head;
141         if (self.team == COLOR_TEAM1) // red
142                 head = find(world, classname, "item_flag_team2"); // blue flag
143         else // blue
144                 head = find(world, classname, "item_flag_team1"); // red flag
145         navigation_routerating(head, ratingscale);
146 };
147
148 void(float ratingscale) havocbot_goalrating_ctf_enemybase =
149 {
150         // div0: needs a change in the CTF code
151 };
152
153 void(float ratingscale) havocbot_goalrating_ctf_ourstolenflag =
154 {
155         local entity head;
156         if (self.team == COLOR_TEAM1) // red
157                 head = find(world, classname, "item_flag_team1"); // red flag
158         else // blue
159                 head = find(world, classname, "item_flag_team2"); // blue flag
160         if (head.cnt != FLAG_BASE)
161                 navigation_routerating(head, ratingscale);
162 };
163
164 void(float ratingscale) havocbot_goalrating_ctf_droppedflags =
165 {
166         local entity redflag, blueflag;
167
168         redflag = find(world, classname, "item_flag_team1");
169         blueflag = find(world, classname, "item_flag_team2");
170
171         if (redflag == world)
172                 error("havocbot: item_flag_team1 missing\n");
173         if (blueflag == world)
174                 error("havocbot: item_flag_team2 missing\n");
175
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);
180 };
181
182 // CTF: (always teamplay)
183
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 =
187 {
188         if (self.bot_strategytime < time)
189         {
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();
196         }
197 }
198
199 //role flag carrier:
200 //pick up armor and health
201 //go to our flag spot
202 void() havocbot_role_ctf_carrier =
203 {
204         if (self.flagcarried == world)
205         {
206                 dprint("changing role to middle\n");
207                 self.havocbot_role = havocbot_role_ctf_middle;
208                 self.havocbot_role_timeout = 0;
209                 return;
210         }
211         if (self.bot_strategytime < time)
212         {
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();
218         }
219 };
220
221 //role offense:
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
227 //go to enemy flag
228 void() havocbot_role_ctf_offense =
229 {
230         local entity f;
231         if (self.flagcarried)
232         {
233                 dprint("changing role to carrier\n");
234                 self.havocbot_role = havocbot_role_ctf_carrier;
235                 self.havocbot_role_timeout = 0;
236                 return;
237         }
238         // check our flag
239         if (self.team == COLOR_TEAM1) // red
240                 f = find(world, classname, "item_flag_team1");
241         else // blue
242                 f = find(world, classname, "item_flag_team2");
243         if (f.cnt != FLAG_BASE && canreach(f))
244         {
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;
249                 return;
250         }
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)
254         {
255                 dprint("changing role to middle\n");
256                 self.havocbot_role = havocbot_role_ctf_middle;
257                 self.havocbot_role_timeout = 0;
258                 return;
259         }
260         if (self.bot_strategytime < time)
261         {
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();
269         }
270 };
271
272 //role interceptor (temporary role):
273 //pick up items
274 //if carrying flag, change role to flag carrier
275 //if our flag is back, change role to previous role
276 //follow our flag
277 //go to least recently visited area
278 void() havocbot_role_ctf_interceptor =
279 {
280         local entity f;
281         if (self.flagcarried)
282         {
283                 dprint("changing role to carrier\n");
284                 self.havocbot_role = havocbot_role_ctf_carrier;
285                 self.havocbot_role_timeout = 0;
286                 return;
287         }
288         // check our flag
289         if (self.team == COLOR_TEAM1) // red
290                 f = find(world, classname, "item_flag_team1");
291         else // blue
292                 f = find(world, classname, "item_flag_team2");
293         if (f.cnt == FLAG_BASE)
294         {
295                 dprint("changing role back\n");
296                 self.havocbot_role = self.havocbot_previous_role;
297                 self.havocbot_role_timeout = 0;
298                 return;
299         }
300
301         if (self.bot_strategytime < time)
302         {
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();
309         }
310 };
311
312 //role middle:
313 //pick up items
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 =
320 {
321         local entity f;
322         if (self.flagcarried)
323         {
324                 dprint("changing role to carrier\n");
325                 self.havocbot_role = havocbot_role_ctf_carrier;
326                 self.havocbot_role_timeout = 0;
327                 return;
328         }
329         // check our flag
330         if (self.team == COLOR_TEAM1) // red
331                 f = find(world, classname, "item_flag_team1");
332         else // blue
333                 f = find(world, classname, "item_flag_team2");
334         if (f.cnt != FLAG_BASE && canreach(f))
335         {
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;
340                 return;
341         }
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)
346         {
347                 if (random() < 0.5)
348                 {
349                         dprint("changing role to offense\n");
350                         self.havocbot_role = havocbot_role_ctf_offense;
351                 }
352                 else
353                 {
354                         dprint("changing role to defense\n");
355                         self.havocbot_role = havocbot_role_ctf_defense;
356                 }
357                 self.havocbot_role_timeout = 0;
358                 return;
359         }
360
361         if (self.bot_strategytime < time)
362         {
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();
370         }
371 };
372
373 //role defense:
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 =
380 {
381         local entity f;
382         if (self.flagcarried)
383         {
384                 dprint("changing role to carrier\n");
385                 self.havocbot_role = havocbot_role_ctf_carrier;
386                 self.havocbot_role_timeout = 0;
387                 return;
388         }
389         // check our flag
390         if (self.team == COLOR_TEAM1) // red
391                 f = find(world, classname, "item_flag_team1");
392         else // blue
393                 f = find(world, classname, "item_flag_team2");
394         if (f.cnt != FLAG_BASE && canreach(f))
395         {
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;
400                 return;
401         }
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)
405         {
406                 dprint("changing role to middle\n");
407                 self.havocbot_role = havocbot_role_ctf_middle;
408                 self.havocbot_role_timeout = 0;
409                 return;
410         }
411         if (self.bot_strategytime < time)
412         {
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();
419         }
420         /*
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")
424         {
425                 self.bot_strategytime = time + random() * 45 + 15;
426                 self.goalentity = world;
427                 head = findchain(classname, "info_ctf_defensepoint");
428                 while (head)
429                 {
430                         if (time > head.count)
431                         {
432                                 self.goalentity = head;
433                                 head.chain = world;
434                         }
435                         head = head.chain;
436                 }
437                 // if there are no defensepoints defined, switch to middle
438                 if (self.goalentity == world)
439                 {
440                         dprint("changing role to middle\n");
441                         self.havocbot_role = havocbot_role_ctf_middle;
442                         self.havocbot_role_timeout = 0;
443                         return;
444                 }
445         }
446         // keep anyone else from taking this spot
447         if (self.goalentity != world)
448                 self.goalentity.count = time + 0.5;
449         */
450 };
451
452 // CTF:
453 // choose a role according to the situation
454 void() havocbot_chooserole_ctf =
455 {
456         local float r;
457         dprint("choose CTF role...\n");
458         if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
459                 self.havocbot_role = havocbot_role_ctf_rogue;
460         else
461         {
462                 r = random() * 3;
463                 if (r < 1)
464                         self.havocbot_role = havocbot_role_ctf_offense;
465                 else if (r < 2)
466                         self.havocbot_role = havocbot_role_ctf_middle;
467                 else
468                         self.havocbot_role = havocbot_role_ctf_defense;
469         }
470 };
471
472 //DOM:
473 //go to best items, or control points you don't own
474 void() havocbot_role_dom =
475 {
476         if (self.bot_strategytime < time)
477         {
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();
485         }
486 };
487
488 //DM:
489 //go to best items
490 void() havocbot_role_dm =
491 {
492         if (self.bot_strategytime < time)
493         {
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();
500         }
501 };
502
503 void() havocbot_chooserole_dm =
504 {
505         self.havocbot_role = havocbot_role_dm;
506 };
507
508 void() havocbot_chooserole_dom =
509 {
510         self.havocbot_role = havocbot_role_dom;
511 };
512
513
514
515
516
517
518 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
519 {
520         local entity head;
521         for(head = world; (head = find(head, classname, "item_kh_key")); )
522         {
523                 if(head.owner == self)
524                         continue;
525                 if(!kh_tracking_enabled)
526                         if(!head.owner || head.team == self.team)
527                                 continue; // skip what I can't see
528                 if(!head.owner)
529                         navigation_routerating(head, ratingscale_dropped);
530                 else if(head.team == self.team)
531                         navigation_routerating(head, ratingscale_team);
532                 else
533                         navigation_routerating(head, ratingscale_enemy);
534         }
535 };
536
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 =
542 {
543         if (!(self.items & IT_KEY1))
544         {
545                 dprint("changing role to freelancer\n");
546                 self.havocbot_role = havocbot_role_kh_freelancer;
547                 self.havocbot_role_timeout = 0;
548                 return;
549         }
550
551         if (self.bot_strategytime < time)
552         {
553                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
554                 navigation_goalrating_start();
555
556                 if(kh_Key_AllOwnedByWhichTeam() == self.team)
557                         havocbot_goalrating_kh(10000, 1, 1); // bring home
558                 else
559                         havocbot_goalrating_kh(4000, 4000, 100); // play defensively
560
561                 havocbot_goalrating_items(10000, self.origin, 10000);
562                 navigation_goalrating_end();
563         }
564 }
565
566 void() havocbot_role_kh_defense =
567 {
568         if (self.items & IT_KEY1)
569         {
570                 dprint("changing role to carrier\n");
571                 self.havocbot_role = havocbot_role_kh_carrier;
572                 self.havocbot_role_timeout = 0;
573                 return;
574         }
575
576         if (!self.havocbot_role_timeout)
577                 self.havocbot_role_timeout = time + random() * 10 + 20;
578         if (time > self.havocbot_role_timeout)
579         {
580                 dprint("changing role to freelancer\n");
581                 self.havocbot_role = havocbot_role_kh_freelancer;
582                 self.havocbot_role_timeout = 0;
583                 return;
584         }
585
586         if (self.bot_strategytime < time)
587         {
588                 float key_owner_team;
589                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
590                 navigation_goalrating_start();
591
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
597                 else
598                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
599
600                 havocbot_goalrating_items(10000, self.origin, 10000);
601                 navigation_goalrating_end();
602         }
603 };
604
605 void() havocbot_role_kh_offense =
606 {
607         if (self.items & IT_KEY1)
608         {
609                 dprint("changing role to carrier\n");
610                 self.havocbot_role = havocbot_role_kh_carrier;
611                 self.havocbot_role_timeout = 0;
612                 return;
613         }
614
615         if (!self.havocbot_role_timeout)
616                 self.havocbot_role_timeout = time + random() * 10 + 20;
617         if (time > self.havocbot_role_timeout)
618         {
619                 dprint("changing role to freelancer\n");
620                 self.havocbot_role = havocbot_role_kh_freelancer;
621                 self.havocbot_role_timeout = 0;
622                 return;
623         }
624
625         if (self.bot_strategytime < time)
626         {
627                 float key_owner_team;
628
629                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
630                 navigation_goalrating_start();
631
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
637                 else
638                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
639
640                 havocbot_goalrating_items(10000, self.origin, 10000);
641                 navigation_goalrating_end();
642         }
643 };
644
645 void() havocbot_role_kh_freelancer =
646 {
647         if (self.items & IT_KEY1)
648         {
649                 dprint("changing role to carrier\n");
650                 self.havocbot_role = havocbot_role_kh_carrier;
651                 self.havocbot_role_timeout = 0;
652                 return;
653         }
654
655         if (!self.havocbot_role_timeout)
656                 self.havocbot_role_timeout = time + random() * 10 + 10;
657         if (time > self.havocbot_role_timeout)
658         {
659                 if (random() < 0.5)
660                 {
661                         dprint("changing role to offense\n");
662                         self.havocbot_role = havocbot_role_kh_offense;
663                 }
664                 else
665                 {
666                         dprint("changing role to defense\n");
667                         self.havocbot_role = havocbot_role_kh_defense;
668                 }
669                 self.havocbot_role_timeout = 0;
670                 return;
671         }
672
673         if (self.bot_strategytime < time)
674         {
675                 float key_owner_team;
676
677                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
678                 navigation_goalrating_start();
679
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
685                 else
686                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
687
688                 havocbot_goalrating_items(10000, self.origin, 10000);
689                 navigation_goalrating_end();
690         }
691 };
692
693
694
695
696
697 void() havocbot_chooserole_kh =
698 {
699         local float r;
700         r = random() * 3;
701         if (r < 1)
702                 self.havocbot_role = havocbot_role_kh_offense;
703         else if (r < 2)
704                 self.havocbot_role = havocbot_role_kh_defense;
705         else
706                 self.havocbot_role = havocbot_role_kh_freelancer;
707 };
708
709 void() havocbot_chooserole =
710 {
711         dprint("choose a role...\n");
712         navigation_routetogoal(world);
713         self.bot_strategytime = -1;
714         if (g_ctf)
715                 havocbot_chooserole_ctf();
716         else if (g_domination)
717                 havocbot_chooserole_dom();
718         else if (g_keyhunt)
719                 havocbot_chooserole_kh();
720         else // assume anything else is deathmatch
721                 havocbot_chooserole_dm();
722 };
723