2 .float havocbot_role_timeout;
3 .void() havocbot_previous_role;
7 float canreach(entity e)
9 return vlen(self.origin - e.origin) < 1500;
12 .float max_armorvalue;
13 float havocbot_pickupevalfunc(entity item)
15 float i, j, rating, base, position, need_shells, need_nails, need_rockets, need_cells;
18 base = item.bot_pickupbasevalue;
20 need_shells = self.weapons & WEPBIT_SHOTGUN;
21 need_nails = self.weapons & WEPBIT_UZI;
22 need_cells = self.weapons & ( WEPBIT_HOOK | WEPBIT_HLAC | WEPBIT_MINSTANEX | WEPBIT_NEX | WEPBIT_ELECTRO | WEPBIT_CRYLINK );
23 need_rockets = self.weapons & ( WEPBIT_ROCKET_LAUNCHER | WEPBIT_GRENADE_LAUNCHER | WEPBIT_HAGAR | WEPBIT_SEEKER );
27 if( self.weapons & item.weapons == item.weapons )
28 rating = 0.5 + bound(0, skill / 20, 0.5);
32 if( bot_custom_weapon )
34 for(i = WEP_FIRST; i < WEP_LAST ; ++i){
35 if( power2of(i-1) & item.weapons != item.weapons )
39 for(j = 0; j < WEP_LAST ; ++j){
41 bot_weapons_far[j] == i ||
42 bot_weapons_mid[j] == i ||
43 bot_weapons_close[j] == i
53 position = WEP_LAST - position;
54 // item.bot_pickupbasevalue is overwritten here
55 base = BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ));
63 if (self.ammo_shells < g_pickup_shells_max && need_cells )
64 rating = rating + max(0, 1 - self.ammo_shells / g_pickup_shells_max);
67 if (self.ammo_nails < g_pickup_nails_max && need_nails )
68 rating = rating + max(0, 1 - self.ammo_nails / g_pickup_nails_max);
70 if (item.ammo_rockets)
71 if (self.ammo_rockets < g_pickup_rockets_max && need_rockets)
72 rating = rating + max(0, 1 - self.ammo_rockets / g_pickup_rockets_max);
75 if (self.ammo_cells < g_pickup_cells_max && need_cells)
76 rating = rating + max(0, 1 - self.ammo_cells / g_pickup_cells_max);
79 if (self.armorvalue < item.max_armorvalue)
80 rating = rating + max(0, 1 - self.armorvalue / item.max_armorvalue);
83 if (self.health < item.max_health)
84 rating = rating + max(0, 1 - self.health / item.max_health);
86 // TODO: if the item is not recognized then default to item.bot_pickupevalfunc(self, item);
91 void havocbot_goalrating_items(float ratingscale, vector org, float sradius)
95 local float rating, d, discard, distance, friend_distance, enemy_distance;
96 ratingscale = ratingscale * 0.0001; // items are rated around 10000 already
97 head = findchainfloat(bot_pickup, TRUE);
101 distance = vlen(head.origin - org);
102 friend_distance = 10000; enemy_distance = 10000;
105 if(!head.solid || distance > sradius ){
114 FOR_EACH_PLAYER(player)
117 if ( self == player || player.deadflag != DEAD_NO)
120 d = vlen(player.origin - head.origin); // distance between player and item
122 if ( player.team == self.team )
124 if ( clienttype(player) != CLIENTTYPE_REAL || discard )
127 if( d > friend_distance)
134 if( head.health && player.health > self.health )
137 if( head.armorvalue && player.armorvalue > self.armorvalue)
141 if( (player.weapons & head.weapons) != head.weapons)
144 if (head.ammo_shells && player.ammo_shells > self.ammo_shells)
147 if (head.ammo_nails && player.ammo_nails > self.ammo_nails)
150 if (head.ammo_rockets && player.ammo_rockets > self.ammo_rockets)
153 if (head.ammo_cells && player.ammo_cells > self.ammo_cells )
160 // If enemy only track distances
161 // TODO: track only if visible ?
162 if( d < enemy_distance )
167 // Rate the item only if no one needs it, or if an enemy is closer to it
168 if ( (enemy_distance < friend_distance && distance < enemy_distance) ||
169 (friend_distance > cvar("bot_ai_friends_aware_pickup_radius") ) || !discard )
171 // rating = head.bot_pickupevalfunc(self, head);
172 rating = havocbot_pickupevalfunc(head);
177 // rating = head.bot_pickupevalfunc(self, head);
178 rating = havocbot_pickupevalfunc(head);
182 navigation_routerating(head, rating * ratingscale, 2000);
188 void havocbot_goalrating_controlpoints(float ratingscale, vector org, float sradius)
191 head = findchain(classname, "dom_controlpoint");
194 if (vlen(head.origin - org) < sradius)
196 if(head.cnt > -1) // this is just being fought for
197 navigation_routerating(head, ratingscale, 5000);
198 else if(head.goalentity.cnt == 0) // unclaimed point
199 navigation_routerating(head, ratingscale * 0.5, 5000);
200 else if(head.goalentity.team != self.team) // other team's point
201 navigation_routerating(head, ratingscale * 0.2, 5000);
208 // LordHavoc: this function was already unused, but for waypoints to be a
209 // useful goal the bots would have to seek out the least-recently-visited
210 // ones, not the closest
211 void havocbot_goalrating_waypoints(float ratingscale, vector org, float sradius)
214 head = findchain(classname, "waypoint");
217 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
218 navigation_routerating(head, ratingscale, 2000);
224 void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
227 local float t, noteam;
228 noteam = ((self.team == 0) || (teamplay == 0)); // fteqcc sucks
229 //dprint("teamplay is "); dprint(ftos(teamplay)); dprint(", own team is ");
230 //dprint(ftos(self.team)); dprint(" -> noteam is "); dprint(ftos(noteam));
233 FOR_EACH_PLAYER(head)
237 if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
239 if (vlen(head.origin - org) > sradius)
242 // rate only visible enemies
244 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
245 if (trace_fraction < 1 || trace_ent != head)
250 if(head.flags & FL_ONGROUND == 0)
252 traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
253 t = pointcontents(trace_endpos + '0 0 1');
254 if (t != CONTENT_SOLID)
256 // TODO: check for trigger_hurt here
259 t = (self.health + self.armorvalue ) / (head.health + head.armorvalue );
260 navigation_routerating(head, t * ratingscale, 2000);
266 void() havocbot_role_ctf_middle;
267 void() havocbot_role_ctf_defense;
268 void() havocbot_role_ctf_offense;
269 void() havocbot_role_ctf_interceptor;
271 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
275 head = findchainfloat(bot_pickup, TRUE);
278 // look for health and armor only
279 if (head.solid) // must be possible to pick up (respawning items don't count)
280 if (head.health || head.armorvalue)
281 if (vlen(head.origin - org) < sradius)
284 //if (!head.bot_pickupevalfunc || head.model == "")
286 // get the value of the item
287 t = head.bot_pickupevalfunc(self, head) * 0.0001;
289 navigation_routerating(head, t * ratingscale, 500);
295 entity ctf_worldflaglist;
296 .entity ctf_worldflagnext;
297 void havocbot_goalrating_ctf_ourflag(float ratingscale)
300 head = ctf_worldflaglist;
303 if (self.team == head.team)
305 head = head.ctf_worldflagnext;
308 navigation_routerating(head, ratingscale, 10000);
311 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
314 head = ctf_worldflaglist;
317 if (self.team != head.team)
319 head = head.ctf_worldflagnext;
322 navigation_routerating(head, ratingscale, 10000);
325 void havocbot_goalrating_ctf_enemybase(float ratingscale)
327 // div0: needs a change in the CTF code
330 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
333 head = ctf_worldflaglist;
336 if (self.team == head.team)
338 head = head.ctf_worldflagnext;
341 if (head.cnt != FLAG_BASE)
342 navigation_routerating(head, ratingscale, 10000);
345 void havocbot_goalrating_ctf_droppedflags(float ratingscale)
348 head = ctf_worldflaglist;
351 if (head.cnt != FLAG_BASE) // flag is carried or out in the field
352 navigation_routerating(head, ratingscale, 10000);
353 head = head.ctf_worldflagnext;
357 // CTF: (always teamplay)
359 //role rogue: (is this used?)
360 //pick up items and dropped flags (with big rating boost to dropped flags)
361 void havocbot_role_ctf_rogue()
363 if (self.bot_strategytime < time)
365 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
366 navigation_goalrating_start();
367 havocbot_goalrating_ctf_droppedflags(5000);
368 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
369 havocbot_goalrating_items(10000, self.origin, 10000);
370 navigation_goalrating_end();
375 //pick up armor and health
376 //go to our flag spot
377 .float bot_cantfindflag;
378 void havocbot_role_ctf_carrier()
380 if (self.flagcarried == world)
382 dprint("changing role to middle\n");
383 self.havocbot_role = havocbot_role_ctf_middle;
384 self.havocbot_role_timeout = 0;
387 if (self.bot_strategytime < time)
389 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
390 navigation_goalrating_start();
391 havocbot_goalrating_ctf_ourflag(50000);
392 if (navigation_bestgoal)
393 self.bot_cantfindflag = time + 10;
394 else if (time > self.bot_cantfindflag)
396 // can't navigate to our own flag :(
397 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
399 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
400 navigation_goalrating_end();
405 //pick up armor and health
406 //if rockets < 25 || health < 100, change role to middle
407 //if carrying flag, change role to flag carrier
408 //if our flag taken, change role to interceptor
409 //(60-90 second timer) change role to middle
411 void havocbot_role_ctf_offense()
414 if (self.flagcarried)
416 dprint("changing role to carrier\n");
417 self.havocbot_role = havocbot_role_ctf_carrier;
418 self.havocbot_role_timeout = 0;
419 self.bot_cantfindflag = time + 10;
423 f = ctf_worldflaglist;
426 if (self.team == f.team)
428 f = f.ctf_worldflagnext;
430 if (f.cnt != FLAG_BASE && canreach(f))
432 dprint("changing role to interceptor\n");
433 self.havocbot_previous_role = self.havocbot_role;
434 self.havocbot_role = havocbot_role_ctf_interceptor;
435 self.havocbot_role_timeout = 0;
438 if (!self.havocbot_role_timeout)
439 self.havocbot_role_timeout = time + random() * 30 + 60;
440 if (time > self.havocbot_role_timeout)
442 dprint("changing role to middle\n");
443 self.havocbot_role = havocbot_role_ctf_middle;
444 self.havocbot_role_timeout = 0;
447 if (self.bot_strategytime < time)
449 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
450 navigation_goalrating_start();
451 havocbot_goalrating_ctf_ourstolenflag(50000);
452 havocbot_goalrating_ctf_enemyflag(30000);
453 havocbot_goalrating_ctf_enemybase(20000);
454 havocbot_goalrating_items(10000, self.origin, 10000);
455 navigation_goalrating_end();
459 //role interceptor (temporary role):
461 //if carrying flag, change role to flag carrier
462 //if our flag is back, change role to previous role
464 //go to least recently visited area
465 void havocbot_role_ctf_interceptor()
468 if (self.flagcarried)
470 dprint("changing role to carrier\n");
471 self.havocbot_role = havocbot_role_ctf_carrier;
472 self.havocbot_role_timeout = 0;
473 self.bot_cantfindflag = time + 10;
477 f = ctf_worldflaglist;
480 if (self.team == f.team)
482 f = f.ctf_worldflagnext;
484 if (f.cnt == FLAG_BASE)
486 dprint("changing role back\n");
487 self.havocbot_role = self.havocbot_previous_role;
488 self.havocbot_role_timeout = 0;
492 if (self.bot_strategytime < time)
494 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
495 navigation_goalrating_start();
496 havocbot_goalrating_ctf_ourstolenflag(50000);
497 havocbot_goalrating_ctf_droppedflags(50000);
498 havocbot_goalrating_items(10000, self.origin, 10000);
499 navigation_goalrating_end();
505 //if carrying flag, change role to flag carrier
506 //if our flag taken, change role to interceptor
507 //if see flag (of either team) follow it (this has many implications)
508 //(10-20 second timer) change role to defense or offense
509 //go to least recently visited area
510 void havocbot_role_ctf_middle()
513 if (self.flagcarried)
515 dprint("changing role to carrier\n");
516 self.havocbot_role = havocbot_role_ctf_carrier;
517 self.havocbot_role_timeout = 0;
518 self.bot_cantfindflag = time + 10;
522 f = ctf_worldflaglist;
525 if (self.team == f.team)
527 f = f.ctf_worldflagnext;
529 if (f.cnt != FLAG_BASE && canreach(f))
531 dprint("changing role to interceptor\n");
532 self.havocbot_previous_role = self.havocbot_role;
533 self.havocbot_role = havocbot_role_ctf_interceptor;
534 self.havocbot_role_timeout = 0;
537 if (!self.havocbot_role_timeout)
538 self.havocbot_role_timeout = time + random() * 10 + 10;
539 if (time > self.havocbot_role_timeout)
543 dprint("changing role to offense\n");
544 self.havocbot_role = havocbot_role_ctf_offense;
548 dprint("changing role to defense\n");
549 self.havocbot_role = havocbot_role_ctf_defense;
551 self.havocbot_role_timeout = 0;
555 if (self.bot_strategytime < time)
557 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
558 navigation_goalrating_start();
559 havocbot_goalrating_ctf_ourstolenflag(50000);
560 havocbot_goalrating_ctf_droppedflags(30000);
561 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
562 havocbot_goalrating_items(10000, self.origin, 10000);
563 navigation_goalrating_end();
568 //if rockets < 25 || health < 100, change role to middle
569 //if carrying flag, change role to flag carrier
570 //if our flag taken, change role to interceptor
571 //(30-50 second timer) change role to middle
572 //move to nearest unclaimed defense spot
573 void havocbot_role_ctf_defense()
576 if (self.flagcarried)
578 dprint("changing role to carrier\n");
579 self.havocbot_role = havocbot_role_ctf_carrier;
580 self.havocbot_role_timeout = 0;
581 self.bot_cantfindflag = time + 10;
585 f = ctf_worldflaglist;
588 if (self.team == f.team)
590 f = f.ctf_worldflagnext;
592 if (f.cnt != FLAG_BASE && canreach(f))
594 dprint("changing role to interceptor\n");
595 self.havocbot_previous_role = self.havocbot_role;
596 self.havocbot_role = havocbot_role_ctf_interceptor;
597 self.havocbot_role_timeout = 0;
600 if (!self.havocbot_role_timeout)
601 self.havocbot_role_timeout = time + random() * 20 + 30;
602 if (time > self.havocbot_role_timeout)
604 dprint("changing role to middle\n");
605 self.havocbot_role = havocbot_role_ctf_middle;
606 self.havocbot_role_timeout = 0;
609 if (self.bot_strategytime < time)
611 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
612 navigation_goalrating_start();
613 havocbot_goalrating_ctf_ourstolenflag(200000);
614 havocbot_goalrating_ctf_droppedflags(50000);
615 havocbot_goalrating_items(10000, f.origin, 10000);
616 navigation_goalrating_end();
619 // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
620 // change position occasionally
621 if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
623 self.bot_strategytime = time + random() * 45 + 15;
624 self.goalentity = world;
625 head = findchain(classname, "info_ctf_defensepoint");
628 if (time > head.count)
630 self.goalentity = head;
635 // if there are no defensepoints defined, switch to middle
636 if (self.goalentity == world)
638 dprint("changing role to middle\n");
639 self.havocbot_role = havocbot_role_ctf_middle;
640 self.havocbot_role_timeout = 0;
644 // keep anyone else from taking this spot
645 if (self.goalentity != world)
646 self.goalentity.count = time + 0.5;
651 // choose a role according to the situation
652 void() havocbot_role_dm;
653 void havocbot_chooserole_ctf()
656 dprint("choose CTF role...\n");
657 if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
658 self.havocbot_role = havocbot_role_ctf_rogue;
663 self.havocbot_role = havocbot_role_ctf_offense;
665 self.havocbot_role = havocbot_role_ctf_middle;
667 self.havocbot_role = havocbot_role_ctf_defense;
672 //go to best items, or control points you don't own
673 void havocbot_role_dom()
675 if (self.bot_strategytime < time)
677 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
678 navigation_goalrating_start();
679 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
680 havocbot_goalrating_items(8000, self.origin, 8000);
681 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
682 //havocbot_goalrating_waypoints(1, self.origin, 1000);
683 navigation_goalrating_end();
689 void havocbot_role_dm()
691 if (self.bot_strategytime < time)
693 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
694 navigation_goalrating_start();
695 havocbot_goalrating_items(10000, self.origin, 10000);
696 havocbot_goalrating_enemyplayers(10000, self.origin, 20000);
697 //havocbot_goalrating_waypoints(1, self.origin, 1000);
698 navigation_goalrating_end();
703 //go to next checkpoint, and annoy enemies
704 .float race_checkpoint;
705 void havocbot_role_race()
708 if (self.bot_strategytime < time)
710 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
711 navigation_goalrating_start();
713 havocbot_goalrating_items(100, self.origin, 10000);
714 havocbot_goalrating_enemyplayers(500, self.origin, 20000);
717 for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
719 if(e.cnt == self.race_checkpoint)
721 navigation_routerating(e, 1000000, 5000);
723 else if(self.race_checkpoint == -1)
725 navigation_routerating(e, 1000000, 5000);
729 navigation_goalrating_end();
733 void havocbot_chooserole_dm()
735 self.havocbot_role = havocbot_role_dm;
738 void havocbot_chooserole_race()
740 self.havocbot_role = havocbot_role_race;
743 void havocbot_chooserole_dom()
745 self.havocbot_role = havocbot_role_dom;
753 entity kh_worldkeylist;
754 .entity kh_worldkeynext;
755 void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
758 for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
760 if(head.owner == self)
762 if(!kh_tracking_enabled)
764 // if it's carried by our team we know about it
765 // otherwise we have to see it to know about it
766 if(!head.owner || head.team != self.team)
768 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
769 if (trace_fraction < 1 && trace_ent != head)
770 continue; // skip what I can't see
774 navigation_routerating(head, ratingscale_dropped, 100000);
775 else if(head.team == self.team)
776 navigation_routerating(head, ratingscale_team, 100000);
778 navigation_routerating(head, ratingscale_enemy, 100000);
782 void() havocbot_role_kh_carrier;
783 void() havocbot_role_kh_defense;
784 void() havocbot_role_kh_offense;
785 void() havocbot_role_kh_freelancer;
786 void havocbot_role_kh_carrier()
788 if (!(self.items & IT_KEY1))
790 dprint("changing role to freelancer\n");
791 self.havocbot_role = havocbot_role_kh_freelancer;
792 self.havocbot_role_timeout = 0;
796 if (self.bot_strategytime < time)
798 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
799 navigation_goalrating_start();
801 if(kh_Key_AllOwnedByWhichTeam() == self.team)
802 havocbot_goalrating_kh(100000, 1, 1); // bring home
804 havocbot_goalrating_kh(40000, 40000, 1000); // play defensively
806 havocbot_goalrating_items(10000, self.origin, 10000);
807 navigation_goalrating_end();
811 void havocbot_role_kh_defense()
813 if (self.items & IT_KEY1)
815 dprint("changing role to carrier\n");
816 self.havocbot_role = havocbot_role_kh_carrier;
817 self.havocbot_role_timeout = 0;
821 if (!self.havocbot_role_timeout)
822 self.havocbot_role_timeout = time + random() * 10 + 20;
823 if (time > self.havocbot_role_timeout)
825 dprint("changing role to freelancer\n");
826 self.havocbot_role = havocbot_role_kh_freelancer;
827 self.havocbot_role_timeout = 0;
831 if (self.bot_strategytime < time)
833 float key_owner_team;
834 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
835 navigation_goalrating_start();
837 key_owner_team = kh_Key_AllOwnedByWhichTeam();
838 if(key_owner_team == self.team)
839 havocbot_goalrating_kh(100000, 1, 1); // defend key carriers
840 else if(key_owner_team == -1)
841 havocbot_goalrating_kh(40000, 10000, 1); // play defensively
843 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
845 havocbot_goalrating_items(10000, self.origin, 10000);
846 navigation_goalrating_end();
850 void havocbot_role_kh_offense()
852 if (self.items & IT_KEY1)
854 dprint("changing role to carrier\n");
855 self.havocbot_role = havocbot_role_kh_carrier;
856 self.havocbot_role_timeout = 0;
860 if (!self.havocbot_role_timeout)
861 self.havocbot_role_timeout = time + random() * 10 + 20;
862 if (time > self.havocbot_role_timeout)
864 dprint("changing role to freelancer\n");
865 self.havocbot_role = havocbot_role_kh_freelancer;
866 self.havocbot_role_timeout = 0;
870 if (self.bot_strategytime < time)
872 float key_owner_team;
874 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
875 navigation_goalrating_start();
877 key_owner_team = kh_Key_AllOwnedByWhichTeam();
878 if(key_owner_team == self.team)
879 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
880 else if(key_owner_team == -1)
881 havocbot_goalrating_kh(1, 10000, 40000); // play offensively
883 havocbot_goalrating_kh(1, 1, 100000); // ATTACK! EMERGENCY!
885 havocbot_goalrating_items(10000, self.origin, 10000);
886 navigation_goalrating_end();
890 void havocbot_role_kh_freelancer()
892 if (self.items & IT_KEY1)
894 dprint("changing role to carrier\n");
895 self.havocbot_role = havocbot_role_kh_carrier;
896 self.havocbot_role_timeout = 0;
900 if (!self.havocbot_role_timeout)
901 self.havocbot_role_timeout = time + random() * 10 + 10;
902 if (time > self.havocbot_role_timeout)
906 dprint("changing role to offense\n");
907 self.havocbot_role = havocbot_role_kh_offense;
911 dprint("changing role to defense\n");
912 self.havocbot_role = havocbot_role_kh_defense;
914 self.havocbot_role_timeout = 0;
918 if (self.bot_strategytime < time)
920 float key_owner_team;
922 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
923 navigation_goalrating_start();
925 key_owner_team = kh_Key_AllOwnedByWhichTeam();
926 if(key_owner_team == self.team)
927 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
928 else if(key_owner_team == -1)
929 havocbot_goalrating_kh(10000, 40000, 10000); // prefer dropped keys
931 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
933 havocbot_goalrating_items(10000, self.origin, 10000);
934 navigation_goalrating_end();
942 void havocbot_chooserole_kh()
947 self.havocbot_role = havocbot_role_kh_offense;
949 self.havocbot_role = havocbot_role_kh_defense;
951 self.havocbot_role = havocbot_role_kh_freelancer;
954 void havocbot_chooserole()
956 dprint("choose a role...\n");
957 navigation_routetogoal(world);
958 self.bot_strategytime = -1;
960 havocbot_chooserole_ctf();
961 else if (g_domination)
962 havocbot_chooserole_dom();
964 havocbot_chooserole_kh();
966 havocbot_chooserole_race();
967 else // assume anything else is deathmatch
968 havocbot_chooserole_dm();