]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/havocbot_roles.qc
fixed several bugs in bots to do with movement and aiming
[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 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);
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);
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);
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);
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 void() havocbot_role_ctf_carrier =
210 {
211         if (self.flagcarried == world)
212         {
213                 dprint("changing role to middle\n");
214                 self.havocbot_role = havocbot_role_ctf_middle;
215                 self.havocbot_role_timeout = 0;
216                 return;
217         }
218         if (self.bot_strategytime < time)
219         {
220                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
221                 navigation_goalrating_start();
222                 havocbot_goalrating_ctf_ourflag(5000);
223                 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
224                 navigation_goalrating_end();
225         }
226 };
227
228 //role offense:
229 //pick up armor and health
230 //if rockets < 25 || health < 100, change role to middle
231 //if carrying flag, change role to flag carrier
232 //if our flag taken, change role to interceptor
233 //(60-90 second timer) change role to middle
234 //go to enemy flag
235 void() havocbot_role_ctf_offense =
236 {
237         local entity f;
238         if (self.flagcarried)
239         {
240                 dprint("changing role to carrier\n");
241                 self.havocbot_role = havocbot_role_ctf_carrier;
242                 self.havocbot_role_timeout = 0;
243                 return;
244         }
245         // check our flag
246         f = flaglist;
247         while (f)
248         {
249                 if (self.team == f.team)
250                         break;
251                 f = f.enemy;
252         }
253         if (f.cnt != FLAG_BASE && canreach(f))
254         {
255                 dprint("changing role to interceptor\n");
256                 self.havocbot_previous_role = self.havocbot_role;
257                 self.havocbot_role = havocbot_role_ctf_interceptor;
258                 self.havocbot_role_timeout = 0;
259                 return;
260         }
261         if (!self.havocbot_role_timeout)
262                 self.havocbot_role_timeout = time + random() * 30 + 60;
263         if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
264         {
265                 dprint("changing role to middle\n");
266                 self.havocbot_role = havocbot_role_ctf_middle;
267                 self.havocbot_role_timeout = 0;
268                 return;
269         }
270         if (self.bot_strategytime < time)
271         {
272                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
273                 navigation_goalrating_start();
274                 havocbot_goalrating_ctf_ourstolenflag(5000);
275                 havocbot_goalrating_ctf_enemyflag(3000);
276                 havocbot_goalrating_ctf_enemybase(2000);
277                 havocbot_goalrating_items(10000, self.origin, 10000);
278                 navigation_goalrating_end();
279         }
280 };
281
282 //role interceptor (temporary role):
283 //pick up items
284 //if carrying flag, change role to flag carrier
285 //if our flag is back, change role to previous role
286 //follow our flag
287 //go to least recently visited area
288 void() havocbot_role_ctf_interceptor =
289 {
290         local entity f;
291         if (self.flagcarried)
292         {
293                 dprint("changing role to carrier\n");
294                 self.havocbot_role = havocbot_role_ctf_carrier;
295                 self.havocbot_role_timeout = 0;
296                 return;
297         }
298         // check our flag
299         f = flaglist;
300         while (f)
301         {
302                 if (self.team == f.team)
303                         break;
304                 f = f.enemy;
305         }
306         if (f.cnt == FLAG_BASE)
307         {
308                 dprint("changing role back\n");
309                 self.havocbot_role = self.havocbot_previous_role;
310                 self.havocbot_role_timeout = 0;
311                 return;
312         }
313
314         if (self.bot_strategytime < time)
315         {
316                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
317                 navigation_goalrating_start();
318                 havocbot_goalrating_ctf_ourstolenflag(5000);
319                 havocbot_goalrating_ctf_droppedflags(5000);
320                 havocbot_goalrating_items(10000, self.origin, 10000);
321                 navigation_goalrating_end();
322         }
323 };
324
325 //role middle:
326 //pick up items
327 //if carrying flag, change role to flag carrier
328 //if our flag taken, change role to interceptor
329 //if see flag (of either team) follow it (this has many implications)
330 //(10-20 second timer) change role to defense or offense
331 //go to least recently visited area
332 void() havocbot_role_ctf_middle =
333 {
334         local entity f;
335         if (self.flagcarried)
336         {
337                 dprint("changing role to carrier\n");
338                 self.havocbot_role = havocbot_role_ctf_carrier;
339                 self.havocbot_role_timeout = 0;
340                 return;
341         }
342         // check our flag
343         f = flaglist;
344         while (f)
345         {
346                 if (self.team == f.team)
347                         break;
348                 f = f.enemy;
349         }
350         if (f.cnt != FLAG_BASE && canreach(f))
351         {
352                 dprint("changing role to interceptor\n");
353                 self.havocbot_previous_role = self.havocbot_role;
354                 self.havocbot_role = havocbot_role_ctf_interceptor;
355                 self.havocbot_role_timeout = 0;
356                 return;
357         }
358         if (!self.havocbot_role_timeout)
359                 self.havocbot_role_timeout = time + random() * 10 + 10;
360         if (time > self.havocbot_role_timeout)
361         if (self.ammo_rockets >= 25)
362         {
363                 if (random() < 0.5)
364                 {
365                         dprint("changing role to offense\n");
366                         self.havocbot_role = havocbot_role_ctf_offense;
367                 }
368                 else
369                 {
370                         dprint("changing role to defense\n");
371                         self.havocbot_role = havocbot_role_ctf_defense;
372                 }
373                 self.havocbot_role_timeout = 0;
374                 return;
375         }
376
377         if (self.bot_strategytime < time)
378         {
379                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
380                 navigation_goalrating_start();
381                 havocbot_goalrating_ctf_ourstolenflag(5000);
382                 havocbot_goalrating_ctf_droppedflags(3000);
383                 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
384                 havocbot_goalrating_items(10000, self.origin, 10000);
385                 navigation_goalrating_end();
386         }
387 };
388
389 //role defense:
390 //if rockets < 25 || health < 100, change role to middle
391 //if carrying flag, change role to flag carrier
392 //if our flag taken, change role to interceptor
393 //(30-50 second timer) change role to middle
394 //move to nearest unclaimed defense spot
395 void() havocbot_role_ctf_defense =
396 {
397         local entity f;
398         if (self.flagcarried)
399         {
400                 dprint("changing role to carrier\n");
401                 self.havocbot_role = havocbot_role_ctf_carrier;
402                 self.havocbot_role_timeout = 0;
403                 return;
404         }
405         // check our flag
406         f = flaglist;
407         while (f)
408         {
409                 if (self.team == f.team)
410                         break;
411                 f = f.enemy;
412         }
413         if (f.cnt != FLAG_BASE && canreach(f))
414         {
415                 dprint("changing role to interceptor\n");
416                 self.havocbot_previous_role = self.havocbot_role;
417                 self.havocbot_role = havocbot_role_ctf_interceptor;
418                 self.havocbot_role_timeout = 0;
419                 return;
420         }
421         if (!self.havocbot_role_timeout)
422                 self.havocbot_role_timeout = time + random() * 20 + 30;
423         if (self.ammo_rockets < 15 || time > self.havocbot_role_timeout)
424         {
425                 dprint("changing role to middle\n");
426                 self.havocbot_role = havocbot_role_ctf_middle;
427                 self.havocbot_role_timeout = 0;
428                 return;
429         }
430         if (self.bot_strategytime < time)
431         {
432                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
433                 navigation_goalrating_start();
434                 havocbot_goalrating_ctf_ourstolenflag(20000);
435                 havocbot_goalrating_ctf_droppedflags(500);
436                 havocbot_goalrating_items(10000, f.origin, 10000);
437                 navigation_goalrating_end();
438         }
439         /*
440         // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
441         // change position occasionally
442         if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
443         {
444                 self.bot_strategytime = time + random() * 45 + 15;
445                 self.goalentity = world;
446                 head = findchain(classname, "info_ctf_defensepoint");
447                 while (head)
448                 {
449                         if (time > head.count)
450                         {
451                                 self.goalentity = head;
452                                 head.chain = world;
453                         }
454                         head = head.chain;
455                 }
456                 // if there are no defensepoints defined, switch to middle
457                 if (self.goalentity == world)
458                 {
459                         dprint("changing role to middle\n");
460                         self.havocbot_role = havocbot_role_ctf_middle;
461                         self.havocbot_role_timeout = 0;
462                         return;
463                 }
464         }
465         // keep anyone else from taking this spot
466         if (self.goalentity != world)
467                 self.goalentity.count = time + 0.5;
468         */
469 };
470
471 // CTF:
472 // choose a role according to the situation
473 void() havocbot_role_dm;
474 void() havocbot_chooserole_ctf =
475 {
476         local float r;
477         dprint("choose CTF role...\n");
478         if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
479                 self.havocbot_role = havocbot_role_ctf_rogue;
480         else
481         {
482                 r = random() * 3;
483                 if (r < 1)
484                         self.havocbot_role = havocbot_role_ctf_offense;
485                 else if (r < 2)
486                         self.havocbot_role = havocbot_role_ctf_middle;
487                 else
488                         self.havocbot_role = havocbot_role_ctf_defense;
489         }
490 };
491
492 //DOM:
493 //go to best items, or control points you don't own
494 void() havocbot_role_dom =
495 {
496         if (self.bot_strategytime < time)
497         {
498                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
499                 navigation_goalrating_start();
500                 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
501                 havocbot_goalrating_items(8000, self.origin, 8000);
502                 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
503                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
504                 navigation_goalrating_end();
505         }
506 };
507
508 //DM:
509 //go to best items
510 void() havocbot_role_dm =
511 {
512         if (self.bot_strategytime < time)
513         {
514                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
515                 navigation_goalrating_start();
516                 havocbot_goalrating_items(10000, self.origin, 10000);
517                 havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
518                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
519                 navigation_goalrating_end();
520         }
521 };
522
523 void() havocbot_chooserole_dm =
524 {
525         self.havocbot_role = havocbot_role_dm;
526 };
527
528 void() havocbot_chooserole_dom =
529 {
530         self.havocbot_role = havocbot_role_dom;
531 };
532
533
534
535
536
537
538 entity kh_keylist;
539 void(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy) havocbot_goalrating_kh =
540 {
541         local entity head;
542         head = kh_keylist;
543         while (head)
544         {
545                 if(head.owner == self)
546                         continue;
547                 if(!kh_tracking_enabled)
548                         if(!head.owner || head.team == self.team)
549                                 continue; // skip what I can't see
550                 if(!head.owner)
551                         navigation_routerating(head, ratingscale_dropped);
552                 else if(head.team == self.team)
553                         navigation_routerating(head, ratingscale_team);
554                 else
555                         navigation_routerating(head, ratingscale_enemy);
556                 head = head.enemy;
557         }
558 };
559
560 void() havocbot_role_kh_carrier;
561 void() havocbot_role_kh_defense;
562 void() havocbot_role_kh_offense;
563 void() havocbot_role_kh_freelancer;
564 void() havocbot_role_kh_carrier =
565 {
566         if (!(self.items & IT_KEY1))
567         {
568                 dprint("changing role to freelancer\n");
569                 self.havocbot_role = havocbot_role_kh_freelancer;
570                 self.havocbot_role_timeout = 0;
571                 return;
572         }
573
574         if (self.bot_strategytime < time)
575         {
576                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
577                 navigation_goalrating_start();
578
579                 if(kh_Key_AllOwnedByWhichTeam() == self.team)
580                         havocbot_goalrating_kh(10000, 1, 1); // bring home
581                 else
582                         havocbot_goalrating_kh(4000, 4000, 100); // play defensively
583
584                 havocbot_goalrating_items(10000, self.origin, 10000);
585                 navigation_goalrating_end();
586         }
587 }
588
589 void() havocbot_role_kh_defense =
590 {
591         if (self.items & IT_KEY1)
592         {
593                 dprint("changing role to carrier\n");
594                 self.havocbot_role = havocbot_role_kh_carrier;
595                 self.havocbot_role_timeout = 0;
596                 return;
597         }
598
599         if (!self.havocbot_role_timeout)
600                 self.havocbot_role_timeout = time + random() * 10 + 20;
601         if (time > self.havocbot_role_timeout)
602         {
603                 dprint("changing role to freelancer\n");
604                 self.havocbot_role = havocbot_role_kh_freelancer;
605                 self.havocbot_role_timeout = 0;
606                 return;
607         }
608
609         if (self.bot_strategytime < time)
610         {
611                 float key_owner_team;
612                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
613                 navigation_goalrating_start();
614
615                 key_owner_team = kh_Key_AllOwnedByWhichTeam();
616                 if(key_owner_team == self.team)
617                         havocbot_goalrating_kh(10000, 1, 1); // defend key carriers
618                 else if(key_owner_team == -1)
619                         havocbot_goalrating_kh(4000, 1000, 1); // play defensively
620                 else
621                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
622
623                 havocbot_goalrating_items(10000, self.origin, 10000);
624                 navigation_goalrating_end();
625         }
626 };
627
628 void() havocbot_role_kh_offense =
629 {
630         if (self.items & IT_KEY1)
631         {
632                 dprint("changing role to carrier\n");
633                 self.havocbot_role = havocbot_role_kh_carrier;
634                 self.havocbot_role_timeout = 0;
635                 return;
636         }
637
638         if (!self.havocbot_role_timeout)
639                 self.havocbot_role_timeout = time + random() * 10 + 20;
640         if (time > self.havocbot_role_timeout)
641         {
642                 dprint("changing role to freelancer\n");
643                 self.havocbot_role = havocbot_role_kh_freelancer;
644                 self.havocbot_role_timeout = 0;
645                 return;
646         }
647
648         if (self.bot_strategytime < time)
649         {
650                 float key_owner_team;
651
652                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
653                 navigation_goalrating_start();
654
655                 key_owner_team = kh_Key_AllOwnedByWhichTeam();
656                 if(key_owner_team == self.team)
657                         havocbot_goalrating_kh(10000, 1, 1); // defend anyway
658                 else if(key_owner_team == -1)
659                         havocbot_goalrating_kh(1, 1000, 4000); // play offensively
660                 else
661                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK! EMERGENCY!
662
663                 havocbot_goalrating_items(10000, self.origin, 10000);
664                 navigation_goalrating_end();
665         }
666 };
667
668 void() havocbot_role_kh_freelancer =
669 {
670         if (self.items & IT_KEY1)
671         {
672                 dprint("changing role to carrier\n");
673                 self.havocbot_role = havocbot_role_kh_carrier;
674                 self.havocbot_role_timeout = 0;
675                 return;
676         }
677
678         if (!self.havocbot_role_timeout)
679                 self.havocbot_role_timeout = time + random() * 10 + 10;
680         if (time > self.havocbot_role_timeout)
681         {
682                 if (random() < 0.5)
683                 {
684                         dprint("changing role to offense\n");
685                         self.havocbot_role = havocbot_role_kh_offense;
686                 }
687                 else
688                 {
689                         dprint("changing role to defense\n");
690                         self.havocbot_role = havocbot_role_kh_defense;
691                 }
692                 self.havocbot_role_timeout = 0;
693                 return;
694         }
695
696         if (self.bot_strategytime < time)
697         {
698                 float key_owner_team;
699
700                 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
701                 navigation_goalrating_start();
702
703                 key_owner_team = kh_Key_AllOwnedByWhichTeam();
704                 if(key_owner_team == self.team)
705                         havocbot_goalrating_kh(10000, 1, 1); // defend anyway
706                 else if(key_owner_team == -1)
707                         havocbot_goalrating_kh(1000, 4000, 1000); // prefer dropped keys
708                 else
709                         havocbot_goalrating_kh(1, 1, 10000); // ATTACK ANYWAY
710
711                 havocbot_goalrating_items(10000, self.origin, 10000);
712                 navigation_goalrating_end();
713         }
714 };
715
716
717
718
719
720 void() havocbot_chooserole_kh =
721 {
722         local float r;
723         r = random() * 3;
724         if (r < 1)
725                 self.havocbot_role = havocbot_role_kh_offense;
726         else if (r < 2)
727                 self.havocbot_role = havocbot_role_kh_defense;
728         else
729                 self.havocbot_role = havocbot_role_kh_freelancer;
730 };
731
732 void() havocbot_chooserole =
733 {
734         dprint("choose a role...\n");
735         navigation_routetogoal(world);
736         self.bot_strategytime = -1;
737         if (g_ctf)
738                 havocbot_chooserole_ctf();
739         else if (g_domination)
740                 havocbot_chooserole_dom();
741         else if (g_keyhunt)
742                 havocbot_chooserole_kh();
743         else // assume anything else is deathmatch
744                 havocbot_chooserole_dm();
745 };
746