]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/havocbot_roles.qc
made cvars like g_ctf only be queried once on startup
[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         head = findchainfloat(bot_pickup, TRUE);
18         while (head)
19         {
20                 if (head.solid) // must be possible to pick up (respawning items don't count)
21                 if (vlen(head.origin - org) < sradius)
22                 {
23                         // debugging
24                         //if (!head.bot_pickupevalfunc || head.model == "")
25                         //      eprint(head);
26                         // get the value of the item
27                         t = head.bot_pickupevalfunc(self, head) * 0.0001;
28                         if (t > 0)
29                                 navigation_routerating(head, t * ratingscale);
30                 }
31                 head = head.chain;
32         }
33 };
34
35 void(float ratingscale, vector org, float sradius) havocbot_goalrating_controlpoints =
36 {
37         local entity head;
38         head = findchain(classname, "dom_controlpoint");
39         while (head)
40         {
41                 if (vlen(head.origin - org) < sradius)
42                 {
43                         if(head.cnt > -1) // this is just being fought for
44                                 navigation_routerating(head, ratingscale);
45                         else if(head.goalentity.cnt == 0) // unclaimed point
46                                 navigation_routerating(head, ratingscale * 0.5);
47                         else if(head.goalentity.team != self.team) // other team's point
48                                 navigation_routerating(head, ratingscale * 0.2);
49                 }
50                 head = head.chain;
51         }
52 };
53
54 void(float ratingscale, vector org, float sradius) havocbot_goalrating_waypoints =
55 {
56         local entity head;
57         head = findchain(classname, "waypoint");
58         while (head)
59         {
60                 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
61                         navigation_routerating(head, ratingscale);
62                 head = head.chain;
63         }
64 };
65
66 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers =
67 {
68         local entity head;
69         local float t, noteam;
70         ratingscale = ratingscale * 1200;
71         noteam = ((self.team == 0) || (teamplay == 0)); // fteqcc sucks
72         //dprint("teamplay is "); dprint(ftos(teamplay)); dprint(", own team is ");
73         //dprint(ftos(self.team)); dprint(" -> noteam is "); dprint(ftos(noteam));
74         //dprint("\n");
75
76         FOR_EACH_PLAYER(head)
77         {
78                 if (self != head)
79                 if (head.health > 0)
80                 if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
81                 if (vlen(head.origin - org) < sradius)
82                 {
83                         t = head.frags + 25;
84                         if (t < 1)
85                                 t = 1;
86                         t = t / (head.health + head.armortype * head.armorvalue);
87                         if (t > 0)
88                         {
89                                 //dprint("found: "); dprint(head.netname); dprint("\n");
90                                 navigation_routerating(head, t * ratingscale);
91                         }
92                 }
93         }
94 };
95
96
97 void() havocbot_role_ctf_middle;
98 void() havocbot_role_ctf_defense;
99 void() havocbot_role_ctf_offense;
100 void() havocbot_role_ctf_interceptor;
101
102 void(float ratingscale, vector org, float sradius) havocbot_goalrating_ctf_carrieritems =
103 {
104         local entity head;
105         local float t;
106         head = findchainfloat(bot_pickup, TRUE);
107         while (head)
108         {
109                 // look for health and armor only
110                 if (head.solid) // must be possible to pick up (respawning items don't count)
111                 if (head.health || head.armorvalue)
112                 if (vlen(head.origin - org) < sradius)
113                 {
114                         // debugging
115                         //if (!head.bot_pickupevalfunc || head.model == "")
116                         //      eprint(head);
117                         // get the value of the item
118                         t = head.bot_pickupevalfunc(self, head) * 0.0001;
119                         if (t > 0)
120                                 navigation_routerating(head, t * ratingscale);
121                 }
122                 head = head.chain;
123         }
124 };
125
126 void(float ratingscale) havocbot_goalrating_ctf_ourflag =
127 {
128         local entity head;
129         if (self.team == COLOR_TEAM1) // red
130                 head = find(world, classname, "item_flag_team1"); // red flag
131         else // blue
132                 head = find(world, classname, "item_flag_team2"); // blue flag
133         navigation_routerating(head, ratingscale);
134 };
135
136 void(float ratingscale) havocbot_goalrating_ctf_enemyflag =
137 {
138         local entity head;
139         if (self.team == COLOR_TEAM1) // red
140                 head = find(world, classname, "item_flag_team2"); // blue flag
141         else // blue
142                 head = find(world, classname, "item_flag_team1"); // red flag
143         navigation_routerating(head, ratingscale);
144 };
145
146 void(float ratingscale) havocbot_goalrating_ctf_enemybase =
147 {
148         // div0: needs a change in the CTF code
149 };
150
151 void(float ratingscale) havocbot_goalrating_ctf_ourstolenflag =
152 {
153         local entity head;
154         if (self.team == COLOR_TEAM1) // red
155                 head = find(world, classname, "item_flag_team1"); // red flag
156         else // blue
157                 head = find(world, classname, "item_flag_team2"); // blue flag
158         if (head.cnt != FLAG_BASE)
159                 navigation_routerating(head, ratingscale);
160 };
161
162 void(float ratingscale) havocbot_goalrating_ctf_droppedflags =
163 {
164         local entity redflag, blueflag;
165
166         redflag = find(world, classname, "item_flag_team1");
167         blueflag = find(world, classname, "item_flag_team2");
168
169         if (redflag == world)
170                 error("havocbot: item_flag_team1 missing\n");
171         if (blueflag == world)
172                 error("havocbot: item_flag_team2 missing\n");
173
174         if (redflag.cnt != FLAG_BASE) // red flag is carried or out in the field
175                 navigation_routerating(redflag, ratingscale);
176         if (blueflag.cnt != FLAG_BASE) // blue flag is carried or out in the field
177                 navigation_routerating(blueflag, ratingscale);
178 };
179
180 // CTF: (always teamplay)
181
182 //role rogue: (is this used?)
183 //pick up items and dropped flags (with big rating boost to dropped flags)
184 void() havocbot_role_ctf_rogue =
185 {
186         if (self.bot_strategytime < time)
187         {
188                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
189                 navigation_goalrating_start();
190                 havocbot_goalrating_ctf_droppedflags(5000);
191                 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
192                 havocbot_goalrating_items(10000, self.origin, 10000);
193                 navigation_goalrating_end();
194         }
195 }
196
197 //role flag carrier:
198 //pick up armor and health
199 //go to our flag spot
200 void() havocbot_role_ctf_carrier =
201 {
202         if (self.flagcarried == world)
203         {
204                 dprint("changing role to middle\n");
205                 self.havocbot_role = havocbot_role_ctf_middle;
206                 self.havocbot_role_timeout = 0;
207                 return;
208         }
209         if (self.bot_strategytime < time)
210         {
211                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
212                 navigation_goalrating_start();
213                 havocbot_goalrating_ctf_ourflag(5000);
214                 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
215                 navigation_goalrating_end();
216         }
217 };
218
219 //role offense:
220 //pick up armor and health
221 //if rockets < 25 || health < 100, change role to middle
222 //if carrying flag, change role to flag carrier
223 //if our flag taken, change role to interceptor
224 //(60-90 second timer) change role to middle
225 //go to enemy flag
226 void() havocbot_role_ctf_offense =
227 {
228         local entity f;
229         if (self.flagcarried)
230         {
231                 dprint("changing role to carrier\n");
232                 self.havocbot_role = havocbot_role_ctf_carrier;
233                 self.havocbot_role_timeout = 0;
234                 return;
235         }
236         // check our flag
237         if (self.team == COLOR_TEAM1) // red
238                 f = find(world, classname, "item_flag_team1");
239         else // blue
240                 f = find(world, classname, "item_flag_team2");
241         if (f.cnt != FLAG_BASE && canreach(f))
242         {
243                 dprint("changing role to interceptor\n");
244                 self.havocbot_previous_role = self.havocbot_role;
245                 self.havocbot_role = havocbot_role_ctf_interceptor;
246                 self.havocbot_role_timeout = 0;
247                 return;
248         }
249         if (!self.havocbot_role_timeout)
250                 self.havocbot_role_timeout = time + random() * 30 + 60;
251         if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
252         {
253                 dprint("changing role to middle\n");
254                 self.havocbot_role = havocbot_role_ctf_middle;
255                 self.havocbot_role_timeout = 0;
256                 return;
257         }
258         if (self.bot_strategytime < time)
259         {
260                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
261                 navigation_goalrating_start();
262                 havocbot_goalrating_ctf_ourstolenflag(5000);
263                 havocbot_goalrating_ctf_enemyflag(3000);
264                 havocbot_goalrating_ctf_enemybase(2000);
265                 havocbot_goalrating_items(10000, self.origin, 10000);
266                 navigation_goalrating_end();
267         }
268 };
269
270 //role interceptor (temporary role):
271 //pick up items
272 //if carrying flag, change role to flag carrier
273 //if our flag is back, change role to previous role
274 //follow our flag
275 //go to least recently visited area
276 void() havocbot_role_ctf_interceptor =
277 {
278         local entity f;
279         if (self.flagcarried)
280         {
281                 dprint("changing role to carrier\n");
282                 self.havocbot_role = havocbot_role_ctf_carrier;
283                 self.havocbot_role_timeout = 0;
284                 return;
285         }
286         // check our flag
287         if (self.team == COLOR_TEAM1) // red
288                 f = find(world, classname, "item_flag_team1");
289         else // blue
290                 f = find(world, classname, "item_flag_team2");
291         if (f.cnt == FLAG_BASE)
292         {
293                 dprint("changing role back\n");
294                 self.havocbot_role = self.havocbot_previous_role;
295                 self.havocbot_role_timeout = 0;
296                 return;
297         }
298
299         if (self.bot_strategytime < time)
300         {
301                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
302                 navigation_goalrating_start();
303                 havocbot_goalrating_ctf_ourstolenflag(5000);
304                 havocbot_goalrating_ctf_droppedflags(5000);
305                 havocbot_goalrating_items(10000, self.origin, 10000);
306                 navigation_goalrating_end();
307         }
308 };
309
310 //role middle:
311 //pick up items
312 //if carrying flag, change role to flag carrier
313 //if our flag taken, change role to interceptor
314 //if see flag (of either team) follow it (this has many implications)
315 //(10-20 second timer) change role to defense or offense
316 //go to least recently visited area
317 void() havocbot_role_ctf_middle =
318 {
319         local entity f;
320         if (self.flagcarried)
321         {
322                 dprint("changing role to carrier\n");
323                 self.havocbot_role = havocbot_role_ctf_carrier;
324                 self.havocbot_role_timeout = 0;
325                 return;
326         }
327         // check our flag
328         if (self.team == COLOR_TEAM1) // red
329                 f = find(world, classname, "item_flag_team1");
330         else // blue
331                 f = find(world, classname, "item_flag_team2");
332         if (f.cnt != FLAG_BASE && canreach(f))
333         {
334                 dprint("changing role to interceptor\n");
335                 self.havocbot_previous_role = self.havocbot_role;
336                 self.havocbot_role = havocbot_role_ctf_interceptor;
337                 self.havocbot_role_timeout = 0;
338                 return;
339         }
340         if (!self.havocbot_role_timeout)
341                 self.havocbot_role_timeout = time + random() * 10 + 10;
342         if (time > self.havocbot_role_timeout)
343         if (self.ammo_rockets >= 25)
344         {
345                 if (random() < 0.5)
346                 {
347                         dprint("changing role to offense\n");
348                         self.havocbot_role = havocbot_role_ctf_offense;
349                 }
350                 else
351                 {
352                         dprint("changing role to defense\n");
353                         self.havocbot_role = havocbot_role_ctf_defense;
354                 }
355                 self.havocbot_role_timeout = 0;
356                 return;
357         }
358
359         if (self.bot_strategytime < time)
360         {
361                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
362                 navigation_goalrating_start();
363                 havocbot_goalrating_ctf_ourstolenflag(5000);
364                 havocbot_goalrating_ctf_droppedflags(3000);
365                 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
366                 havocbot_goalrating_items(10000, self.origin, 10000);
367                 navigation_goalrating_end();
368         }
369 };
370
371 //role defense:
372 //if rockets < 25 || health < 100, change role to middle
373 //if carrying flag, change role to flag carrier
374 //if our flag taken, change role to interceptor
375 //(30-50 second timer) change role to middle
376 //move to nearest unclaimed defense spot
377 void() havocbot_role_ctf_defense =
378 {
379         local entity f;
380         if (self.flagcarried)
381         {
382                 dprint("changing role to carrier\n");
383                 self.havocbot_role = havocbot_role_ctf_carrier;
384                 self.havocbot_role_timeout = 0;
385                 return;
386         }
387         // check our flag
388         if (self.team == COLOR_TEAM1) // red
389                 f = find(world, classname, "item_flag_team1");
390         else // blue
391                 f = find(world, classname, "item_flag_team2");
392         if (f.cnt != FLAG_BASE && canreach(f))
393         {
394                 dprint("changing role to interceptor\n");
395                 self.havocbot_previous_role = self.havocbot_role;
396                 self.havocbot_role = havocbot_role_ctf_interceptor;
397                 self.havocbot_role_timeout = 0;
398                 return;
399         }
400         if (!self.havocbot_role_timeout)
401                 self.havocbot_role_timeout = time + random() * 20 + 30;
402         if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
403         {
404                 dprint("changing role to middle\n");
405                 self.havocbot_role = havocbot_role_ctf_middle;
406                 self.havocbot_role_timeout = 0;
407                 return;
408         }
409         if (self.bot_strategytime < time)
410         {
411                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
412                 navigation_goalrating_start();
413                 havocbot_goalrating_ctf_ourstolenflag(20000);
414                 havocbot_goalrating_ctf_droppedflags(500);
415                 havocbot_goalrating_items(10000, f.origin, 10000);
416                 navigation_goalrating_end();
417         }
418         /*
419         // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
420         // change position occasionally
421         if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
422         {
423                 self.bot_strategytime = time + random() * 45 + 15;
424                 self.goalentity = world;
425                 head = findchain(classname, "info_ctf_defensepoint");
426                 while (head)
427                 {
428                         if (time > head.count)
429                         {
430                                 self.goalentity = head;
431                                 head.chain = world;
432                         }
433                         head = head.chain;
434                 }
435                 // if there are no defensepoints defined, switch to middle
436                 if (self.goalentity == world)
437                 {
438                         dprint("changing role to middle\n");
439                         self.havocbot_role = havocbot_role_ctf_middle;
440                         self.havocbot_role_timeout = 0;
441                         return;
442                 }
443         }
444         // keep anyone else from taking this spot
445         if (self.goalentity != world)
446                 self.goalentity.count = time + 0.5;
447         */
448 };
449
450 // CTF:
451 // choose a role according to the situation
452 void() havocbot_chooserole_ctf =
453 {
454         local float r;
455         dprint("choose CTF role...\n");
456         if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
457                 self.havocbot_role = havocbot_role_ctf_rogue;
458         else
459         {
460                 r = random() * 3;
461                 if (r < 1)
462                         self.havocbot_role = havocbot_role_ctf_offense;
463                 else if (r < 2)
464                         self.havocbot_role = havocbot_role_ctf_middle;
465                 else
466                         self.havocbot_role = havocbot_role_ctf_defense;
467         }
468 };
469
470 //DOM:
471 //go to best items, or control points you don't own
472 void() havocbot_role_dom =
473 {
474         if (self.bot_strategytime < time)
475         {
476                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
477                 navigation_goalrating_start();
478                 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
479                 havocbot_goalrating_items(8000, self.origin, 8000);
480                 //havocbot_goalrating_enemyplayers(1, self.origin, 2000);
481                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
482                 navigation_goalrating_end();
483         }
484 };
485
486 //DM:
487 //go to best items
488 void() havocbot_role_dm =
489 {
490         if (self.bot_strategytime < time)
491         {
492                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
493                 navigation_goalrating_start();
494                 havocbot_goalrating_items(10000, self.origin, 10000);
495                 havocbot_goalrating_enemyplayers(1, self.origin, 20000);
496                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
497                 navigation_goalrating_end();
498         }
499 };
500
501 void() havocbot_chooserole_dm =
502 {
503         self.havocbot_role = havocbot_role_dm;
504 };
505
506 void() havocbot_chooserole_dom =
507 {
508         self.havocbot_role = havocbot_role_dom;
509 };
510
511
512
513
514
515
516 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
517 {
518         local entity head;
519         for(head = world; (head = find(head, classname, "item_kh_key")); )
520         {
521                 if(head.owner == self)
522                         continue;
523                 if(!kh_tracking_enabled)
524                         if(!head.owner || head.team == self.team)
525                                 continue; // skip what I can't see
526                 if(!head.owner)
527                         navigation_routerating(head, ratingscale_dropped);
528                 else if(head.team == self.team)
529                         navigation_routerating(head, ratingscale_team);
530                 else
531                         navigation_routerating(head, ratingscale_enemy);
532         }
533 };
534
535 void() havocbot_role_kh_carrier;
536 void() havocbot_role_kh_defense;
537 void() havocbot_role_kh_offense;
538 void() havocbot_role_kh_freelancer;
539 void() havocbot_role_kh_carrier =
540 {
541         if (!(self.items & IT_KEY1))
542         {
543                 dprint("changing role to freelancer\n");
544                 self.havocbot_role = havocbot_role_kh_freelancer;
545                 self.havocbot_role_timeout = 0;
546                 return;
547         }
548
549         if (self.bot_strategytime < time)
550         {
551                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
552                 navigation_goalrating_start();
553
554                 if(kh_Key_AllOwnedByWhichTeam() == self.team)
555                         havocbot_goalrating_kh(10000, 1, 1); // bring home
556                 else
557                         havocbot_goalrating_kh(4000, 4000, 100); // play defensively
558
559                 havocbot_goalrating_items(10000, self.origin, 10000);
560                 navigation_goalrating_end();
561         }
562 }
563
564 void() havocbot_role_kh_defense =
565 {
566         if (self.items & IT_KEY1)
567         {
568                 dprint("changing role to carrier\n");
569                 self.havocbot_role = havocbot_role_kh_carrier;
570                 self.havocbot_role_timeout = 0;
571                 return;
572         }
573
574         if (!self.havocbot_role_timeout)
575                 self.havocbot_role_timeout = time + random() * 10 + 20;
576         if (time > self.havocbot_role_timeout)
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                 float key_owner_team;
587                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
588                 navigation_goalrating_start();
589
590                 key_owner_team = kh_Key_AllOwnedByWhichTeam();
591                 if(key_owner_team == self.team)
592                         havocbot_goalrating_kh(10000, 1, 1); // defend key carriers
593                 else if(key_owner_team == -1)
594                         havocbot_goalrating_kh(4000, 1000, 1); // play defensively
595                 else
596                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
597
598                 havocbot_goalrating_items(10000, self.origin, 10000);
599                 navigation_goalrating_end();
600         }
601 };
602
603 void() havocbot_role_kh_offense =
604 {
605         if (self.items & IT_KEY1)
606         {
607                 dprint("changing role to carrier\n");
608                 self.havocbot_role = havocbot_role_kh_carrier;
609                 self.havocbot_role_timeout = 0;
610                 return;
611         }
612
613         if (!self.havocbot_role_timeout)
614                 self.havocbot_role_timeout = time + random() * 10 + 20;
615         if (time > self.havocbot_role_timeout)
616         {
617                 dprint("changing role to freelancer\n");
618                 self.havocbot_role = havocbot_role_kh_freelancer;
619                 self.havocbot_role_timeout = 0;
620                 return;
621         }
622
623         if (self.bot_strategytime < time)
624         {
625                 float key_owner_team;
626
627                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
628                 navigation_goalrating_start();
629
630                 key_owner_team = kh_Key_AllOwnedByWhichTeam();
631                 if(key_owner_team == self.team)
632                         havocbot_goalrating_kh(10000, 1, 1); // defend anyway
633                 else if(key_owner_team == -1)
634                         havocbot_goalrating_kh(1, 1000, 4000); // play offensively
635                 else
636                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
637
638                 havocbot_goalrating_items(10000, self.origin, 10000);
639                 navigation_goalrating_end();
640         }
641 };
642
643 void() havocbot_role_kh_freelancer =
644 {
645         if (self.items & IT_KEY1)
646         {
647                 dprint("changing role to carrier\n");
648                 self.havocbot_role = havocbot_role_kh_carrier;
649                 self.havocbot_role_timeout = 0;
650                 return;
651         }
652
653         if (!self.havocbot_role_timeout)
654                 self.havocbot_role_timeout = time + random() * 10 + 10;
655         if (time > self.havocbot_role_timeout)
656         {
657                 if (random() < 0.5)
658                 {
659                         dprint("changing role to offense\n");
660                         self.havocbot_role = havocbot_role_kh_offense;
661                 }
662                 else
663                 {
664                         dprint("changing role to defense\n");
665                         self.havocbot_role = havocbot_role_kh_defense;
666                 }
667                 self.havocbot_role_timeout = 0;
668                 return;
669         }
670
671         if (self.bot_strategytime < time)
672         {
673                 float key_owner_team;
674
675                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
676                 navigation_goalrating_start();
677
678                 key_owner_team = kh_Key_AllOwnedByWhichTeam();
679                 if(key_owner_team == self.team)
680                         havocbot_goalrating_kh(10000, 1, 1); // defend anyway
681                 else if(key_owner_team == -1)
682                         havocbot_goalrating_kh(1000, 4000, 1000); // prefer dropped keys
683                 else
684                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
685
686                 havocbot_goalrating_items(10000, self.origin, 10000);
687                 navigation_goalrating_end();
688         }
689 };
690
691
692
693
694
695 void() havocbot_chooserole_kh =
696 {
697         local float r;
698         r = random() * 3;
699         if (r < 1)
700                 self.havocbot_role = havocbot_role_kh_offense;
701         else if (r < 2)
702                 self.havocbot_role = havocbot_role_kh_defense;
703         else
704                 self.havocbot_role = havocbot_role_kh_freelancer;
705 };
706
707 void() havocbot_chooserole =
708 {
709         dprint("choose a role...\n");
710         navigation_routetogoal(world);
711         self.bot_strategytime = -1;
712         if (g_ctf)
713                 havocbot_chooserole_ctf();
714         else if (cvar("g_domination"))
715                 havocbot_chooserole_dom();
716         else if (g_keyhunt)
717                 havocbot_chooserole_kh();
718         else // assume anything else is deathmatch
719                 havocbot_chooserole_dm();
720 };
721