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 ){
110 // Check if the item can be picked up safely
111 if(head.classname == "droppedweapon")
113 traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
115 d = pointcontents(trace_endpos + '0 0 1');
116 if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
121 if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
132 FOR_EACH_PLAYER(player)
135 if ( self == player || player.deadflag )
138 d = vlen(player.origin - head.origin); // distance between player and item
140 if ( player.team == self.team )
142 if ( clienttype(player) != CLIENTTYPE_REAL || discard )
145 if( d > friend_distance)
152 if( head.health && player.health > self.health )
155 if( head.armorvalue && player.armorvalue > self.armorvalue)
159 if( (player.weapons & head.weapons) != head.weapons)
162 if (head.ammo_shells && player.ammo_shells > self.ammo_shells)
165 if (head.ammo_nails && player.ammo_nails > self.ammo_nails)
168 if (head.ammo_rockets && player.ammo_rockets > self.ammo_rockets)
171 if (head.ammo_cells && player.ammo_cells > self.ammo_cells )
178 // If enemy only track distances
179 // TODO: track only if visible ?
180 if( d < enemy_distance )
185 // Rate the item only if no one needs it, or if an enemy is closer to it
186 if ( (enemy_distance < friend_distance && distance < enemy_distance) ||
187 (friend_distance > cvar("bot_ai_friends_aware_pickup_radius") ) || !discard )
189 // rating = head.bot_pickupevalfunc(self, head);
190 rating = havocbot_pickupevalfunc(head);
195 // rating = head.bot_pickupevalfunc(self, head);
196 rating = havocbot_pickupevalfunc(head);
200 navigation_routerating(head, rating * ratingscale, 2000);
206 void havocbot_goalrating_controlpoints(float ratingscale, vector org, float sradius)
209 head = findchain(classname, "dom_controlpoint");
212 if (vlen(head.origin - org) < sradius)
214 if(head.cnt > -1) // this is just being fought for
215 navigation_routerating(head, ratingscale, 5000);
216 else if(head.goalentity.cnt == 0) // unclaimed point
217 navigation_routerating(head, ratingscale * 0.5, 5000);
218 else if(head.goalentity.team != self.team) // other team's point
219 navigation_routerating(head, ratingscale * 0.2, 5000);
226 // LordHavoc: this function was already unused, but for waypoints to be a
227 // useful goal the bots would have to seek out the least-recently-visited
228 // ones, not the closest
229 void havocbot_goalrating_waypoints(float ratingscale, vector org, float sradius)
232 head = findchain(classname, "waypoint");
235 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
236 navigation_routerating(head, ratingscale, 2000);
242 void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
245 local float t, noteam;
246 noteam = ((self.team == 0) || (teamplay == 0)); // fteqcc sucks
248 FOR_EACH_PLAYER(head)
252 if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
254 if (vlen(head.origin - org) > sradius)
257 // rate only visible enemies
259 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
260 if (trace_fraction < 1 || trace_ent != head)
264 if(head.flags & FL_INWATER || head.flags & FL_PARTIALGROUND)
268 if(head.flags & FL_ONGROUND == 0)
270 traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
271 t = pointcontents(trace_endpos + '0 0 1');
272 if( t != CONTENT_SOLID )
273 if(t & CONTENT_WATER || t & CONTENT_SLIME || t & CONTENT_LAVA)
275 if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
279 t = (self.health + self.armorvalue ) / (head.health + head.armorvalue );
280 navigation_routerating(head, t * ratingscale, 2000);
286 void() havocbot_role_ctf_middle;
287 void() havocbot_role_ctf_defense;
288 void() havocbot_role_ctf_offense;
289 void() havocbot_role_ctf_interceptor;
291 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
295 head = findchainfloat(bot_pickup, TRUE);
298 // look for health and armor only
299 if (head.solid) // must be possible to pick up (respawning items don't count)
300 if (head.health || head.armorvalue)
301 if (vlen(head.origin - org) < sradius)
304 //if (!head.bot_pickupevalfunc || head.model == "")
306 // get the value of the item
307 t = head.bot_pickupevalfunc(self, head) * 0.0001;
309 navigation_routerating(head, t * ratingscale, 500);
315 entity ctf_worldflaglist;
316 .entity ctf_worldflagnext;
317 void havocbot_goalrating_ctf_ourflag(float ratingscale)
320 head = ctf_worldflaglist;
323 if (self.team == head.team)
325 head = head.ctf_worldflagnext;
328 navigation_routerating(head, ratingscale, 10000);
331 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
334 head = ctf_worldflaglist;
337 if (self.team != head.team)
339 head = head.ctf_worldflagnext;
342 navigation_routerating(head, ratingscale, 10000);
345 void havocbot_goalrating_ctf_enemybase(float ratingscale)
347 // div0: needs a change in the CTF code
350 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
353 head = ctf_worldflaglist;
356 if (self.team == head.team)
358 head = head.ctf_worldflagnext;
361 if (head.cnt != FLAG_BASE)
362 navigation_routerating(head, ratingscale, 10000);
365 void havocbot_goalrating_ctf_droppedflags(float ratingscale)
368 head = ctf_worldflaglist;
371 if (head.cnt != FLAG_BASE) // flag is carried or out in the field
372 navigation_routerating(head, ratingscale, 10000);
373 head = head.ctf_worldflagnext;
377 // CTF: (always teamplay)
379 //role rogue: (is this used?)
380 //pick up items and dropped flags (with big rating boost to dropped flags)
381 void havocbot_role_ctf_rogue()
383 if (self.bot_strategytime < time)
385 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
386 navigation_goalrating_start();
387 havocbot_goalrating_ctf_droppedflags(5000);
388 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
389 havocbot_goalrating_items(10000, self.origin, 10000);
390 navigation_goalrating_end();
395 //pick up armor and health
396 //go to our flag spot
397 .float bot_cantfindflag;
398 void havocbot_role_ctf_carrier()
400 if (self.flagcarried == world)
402 dprint("changing role to middle\n");
403 self.havocbot_role = havocbot_role_ctf_middle;
404 self.havocbot_role_timeout = 0;
407 if (self.bot_strategytime < time)
409 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
410 navigation_goalrating_start();
411 havocbot_goalrating_ctf_ourflag(50000);
412 if (navigation_bestgoal)
413 self.bot_cantfindflag = time + 10;
414 else if (time > self.bot_cantfindflag)
416 // can't navigate to our own flag :(
417 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
419 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
420 navigation_goalrating_end();
425 //pick up armor and health
426 //if rockets < 25 || health < 100, change role to middle
427 //if carrying flag, change role to flag carrier
428 //if our flag taken, change role to interceptor
429 //(60-90 second timer) change role to middle
431 void havocbot_role_ctf_offense()
434 if (self.flagcarried)
436 dprint("changing role to carrier\n");
437 self.havocbot_role = havocbot_role_ctf_carrier;
438 self.havocbot_role_timeout = 0;
439 self.bot_cantfindflag = time + 10;
443 f = ctf_worldflaglist;
446 if (self.team == f.team)
448 f = f.ctf_worldflagnext;
450 if (f.cnt != FLAG_BASE && canreach(f))
452 dprint("changing role to interceptor\n");
453 self.havocbot_previous_role = self.havocbot_role;
454 self.havocbot_role = havocbot_role_ctf_interceptor;
455 self.havocbot_role_timeout = 0;
458 if (!self.havocbot_role_timeout)
459 self.havocbot_role_timeout = time + random() * 30 + 60;
460 if (time > self.havocbot_role_timeout)
462 dprint("changing role to middle\n");
463 self.havocbot_role = havocbot_role_ctf_middle;
464 self.havocbot_role_timeout = 0;
467 if (self.bot_strategytime < time)
469 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
470 navigation_goalrating_start();
471 havocbot_goalrating_ctf_ourstolenflag(50000);
472 havocbot_goalrating_ctf_enemyflag(30000);
473 havocbot_goalrating_ctf_enemybase(20000);
474 havocbot_goalrating_items(10000, self.origin, 10000);
475 navigation_goalrating_end();
479 //role interceptor (temporary role):
481 //if carrying flag, change role to flag carrier
482 //if our flag is back, change role to previous role
484 //go to least recently visited area
485 void havocbot_role_ctf_interceptor()
488 if (self.flagcarried)
490 dprint("changing role to carrier\n");
491 self.havocbot_role = havocbot_role_ctf_carrier;
492 self.havocbot_role_timeout = 0;
493 self.bot_cantfindflag = time + 10;
497 f = ctf_worldflaglist;
500 if (self.team == f.team)
502 f = f.ctf_worldflagnext;
504 if (f.cnt == FLAG_BASE)
506 dprint("changing role back\n");
507 self.havocbot_role = self.havocbot_previous_role;
508 self.havocbot_role_timeout = 0;
512 if (self.bot_strategytime < time)
514 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
515 navigation_goalrating_start();
516 havocbot_goalrating_ctf_ourstolenflag(50000);
517 havocbot_goalrating_ctf_droppedflags(50000);
518 havocbot_goalrating_items(10000, self.origin, 10000);
519 navigation_goalrating_end();
525 //if carrying flag, change role to flag carrier
526 //if our flag taken, change role to interceptor
527 //if see flag (of either team) follow it (this has many implications)
528 //(10-20 second timer) change role to defense or offense
529 //go to least recently visited area
530 void havocbot_role_ctf_middle()
533 if (self.flagcarried)
535 dprint("changing role to carrier\n");
536 self.havocbot_role = havocbot_role_ctf_carrier;
537 self.havocbot_role_timeout = 0;
538 self.bot_cantfindflag = time + 10;
542 f = ctf_worldflaglist;
545 if (self.team == f.team)
547 f = f.ctf_worldflagnext;
549 if (f.cnt != FLAG_BASE && canreach(f))
551 dprint("changing role to interceptor\n");
552 self.havocbot_previous_role = self.havocbot_role;
553 self.havocbot_role = havocbot_role_ctf_interceptor;
554 self.havocbot_role_timeout = 0;
557 if (!self.havocbot_role_timeout)
558 self.havocbot_role_timeout = time + random() * 10 + 10;
559 if (time > self.havocbot_role_timeout)
563 dprint("changing role to offense\n");
564 self.havocbot_role = havocbot_role_ctf_offense;
568 dprint("changing role to defense\n");
569 self.havocbot_role = havocbot_role_ctf_defense;
571 self.havocbot_role_timeout = 0;
575 if (self.bot_strategytime < time)
577 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
578 navigation_goalrating_start();
579 havocbot_goalrating_ctf_ourstolenflag(50000);
580 havocbot_goalrating_ctf_droppedflags(30000);
581 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
582 havocbot_goalrating_items(10000, self.origin, 10000);
583 navigation_goalrating_end();
588 //if rockets < 25 || health < 100, change role to middle
589 //if carrying flag, change role to flag carrier
590 //if our flag taken, change role to interceptor
591 //(30-50 second timer) change role to middle
592 //move to nearest unclaimed defense spot
593 void havocbot_role_ctf_defense()
596 if (self.flagcarried)
598 dprint("changing role to carrier\n");
599 self.havocbot_role = havocbot_role_ctf_carrier;
600 self.havocbot_role_timeout = 0;
601 self.bot_cantfindflag = time + 10;
605 f = ctf_worldflaglist;
608 if (self.team == f.team)
610 f = f.ctf_worldflagnext;
612 if (f.cnt != FLAG_BASE && canreach(f))
614 dprint("changing role to interceptor\n");
615 self.havocbot_previous_role = self.havocbot_role;
616 self.havocbot_role = havocbot_role_ctf_interceptor;
617 self.havocbot_role_timeout = 0;
620 if (!self.havocbot_role_timeout)
621 self.havocbot_role_timeout = time + random() * 20 + 30;
622 if (time > self.havocbot_role_timeout)
624 dprint("changing role to middle\n");
625 self.havocbot_role = havocbot_role_ctf_middle;
626 self.havocbot_role_timeout = 0;
629 if (self.bot_strategytime < time)
631 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
632 navigation_goalrating_start();
633 havocbot_goalrating_ctf_ourstolenflag(200000);
634 havocbot_goalrating_ctf_droppedflags(50000);
635 havocbot_goalrating_items(10000, f.origin, 10000);
636 navigation_goalrating_end();
639 // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
640 // change position occasionally
641 if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
643 self.bot_strategytime = time + random() * 45 + 15;
644 self.goalentity = world;
645 head = findchain(classname, "info_ctf_defensepoint");
648 if (time > head.count)
650 self.goalentity = head;
655 // if there are no defensepoints defined, switch to middle
656 if (self.goalentity == world)
658 dprint("changing role to middle\n");
659 self.havocbot_role = havocbot_role_ctf_middle;
660 self.havocbot_role_timeout = 0;
664 // keep anyone else from taking this spot
665 if (self.goalentity != world)
666 self.goalentity.count = time + 0.5;
671 // choose a role according to the situation
672 void() havocbot_role_dm;
673 void havocbot_chooserole_ctf()
676 dprint("choose CTF role...\n");
677 if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
678 self.havocbot_role = havocbot_role_ctf_rogue;
683 self.havocbot_role = havocbot_role_ctf_offense;
685 self.havocbot_role = havocbot_role_ctf_middle;
687 self.havocbot_role = havocbot_role_ctf_defense;
692 //go to best items, or control points you don't own
693 void havocbot_role_dom()
695 if (self.bot_strategytime < time)
697 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
698 navigation_goalrating_start();
699 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
700 havocbot_goalrating_items(8000, self.origin, 8000);
701 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
702 //havocbot_goalrating_waypoints(1, self.origin, 1000);
703 navigation_goalrating_end();
709 void havocbot_role_dm()
711 if (self.bot_strategytime < time)
713 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
714 navigation_goalrating_start();
715 havocbot_goalrating_items(10000, self.origin, 10000);
716 havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
717 //havocbot_goalrating_waypoints(1, self.origin, 1000);
718 navigation_goalrating_end();
723 //go to next checkpoint, and annoy enemies
724 .float race_checkpoint;
725 void havocbot_role_race()
728 if (self.bot_strategytime < time)
730 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
731 navigation_goalrating_start();
733 havocbot_goalrating_items(100, self.origin, 10000);
734 havocbot_goalrating_enemyplayers(500, self.origin, 20000);
737 for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
739 if(e.cnt == self.race_checkpoint)
741 navigation_routerating(e, 1000000, 5000);
743 else if(self.race_checkpoint == -1)
745 navigation_routerating(e, 1000000, 5000);
749 navigation_goalrating_end();
753 void havocbot_chooserole_dm()
755 self.havocbot_role = havocbot_role_dm;
758 void havocbot_chooserole_race()
760 self.havocbot_role = havocbot_role_race;
763 void havocbot_chooserole_dom()
765 self.havocbot_role = havocbot_role_dom;
773 entity kh_worldkeylist;
774 .entity kh_worldkeynext;
775 void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
778 for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
780 if(head.owner == self)
782 if(!kh_tracking_enabled)
784 // if it's carried by our team we know about it
785 // otherwise we have to see it to know about it
786 if(!head.owner || head.team != self.team)
788 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
789 if (trace_fraction < 1 && trace_ent != head)
790 continue; // skip what I can't see
794 navigation_routerating(head, ratingscale_dropped, 100000);
795 else if(head.team == self.team)
796 navigation_routerating(head, ratingscale_team, 100000);
798 navigation_routerating(head, ratingscale_enemy, 100000);
802 void() havocbot_role_kh_carrier;
803 void() havocbot_role_kh_defense;
804 void() havocbot_role_kh_offense;
805 void() havocbot_role_kh_freelancer;
806 void havocbot_role_kh_carrier()
808 if (!(self.items & IT_KEY1))
810 dprint("changing role to freelancer\n");
811 self.havocbot_role = havocbot_role_kh_freelancer;
812 self.havocbot_role_timeout = 0;
816 if (self.bot_strategytime < time)
818 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
819 navigation_goalrating_start();
821 if(kh_Key_AllOwnedByWhichTeam() == self.team)
822 havocbot_goalrating_kh(100000, 1, 1); // bring home
824 havocbot_goalrating_kh(40000, 40000, 1000); // play defensively
826 havocbot_goalrating_items(10000, self.origin, 10000);
827 navigation_goalrating_end();
831 void havocbot_role_kh_defense()
833 if (self.items & IT_KEY1)
835 dprint("changing role to carrier\n");
836 self.havocbot_role = havocbot_role_kh_carrier;
837 self.havocbot_role_timeout = 0;
841 if (!self.havocbot_role_timeout)
842 self.havocbot_role_timeout = time + random() * 10 + 20;
843 if (time > self.havocbot_role_timeout)
845 dprint("changing role to freelancer\n");
846 self.havocbot_role = havocbot_role_kh_freelancer;
847 self.havocbot_role_timeout = 0;
851 if (self.bot_strategytime < time)
853 float key_owner_team;
854 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
855 navigation_goalrating_start();
857 key_owner_team = kh_Key_AllOwnedByWhichTeam();
858 if(key_owner_team == self.team)
859 havocbot_goalrating_kh(100000, 1, 1); // defend key carriers
860 else if(key_owner_team == -1)
861 havocbot_goalrating_kh(40000, 10000, 1); // play defensively
863 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
865 havocbot_goalrating_items(10000, self.origin, 10000);
866 navigation_goalrating_end();
870 void havocbot_role_kh_offense()
872 if (self.items & IT_KEY1)
874 dprint("changing role to carrier\n");
875 self.havocbot_role = havocbot_role_kh_carrier;
876 self.havocbot_role_timeout = 0;
880 if (!self.havocbot_role_timeout)
881 self.havocbot_role_timeout = time + random() * 10 + 20;
882 if (time > self.havocbot_role_timeout)
884 dprint("changing role to freelancer\n");
885 self.havocbot_role = havocbot_role_kh_freelancer;
886 self.havocbot_role_timeout = 0;
890 if (self.bot_strategytime < time)
892 float key_owner_team;
894 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
895 navigation_goalrating_start();
897 key_owner_team = kh_Key_AllOwnedByWhichTeam();
898 if(key_owner_team == self.team)
899 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
900 else if(key_owner_team == -1)
901 havocbot_goalrating_kh(1, 10000, 40000); // play offensively
903 havocbot_goalrating_kh(1, 1, 100000); // ATTACK! EMERGENCY!
905 havocbot_goalrating_items(10000, self.origin, 10000);
906 navigation_goalrating_end();
910 void havocbot_role_kh_freelancer()
912 if (self.items & IT_KEY1)
914 dprint("changing role to carrier\n");
915 self.havocbot_role = havocbot_role_kh_carrier;
916 self.havocbot_role_timeout = 0;
920 if (!self.havocbot_role_timeout)
921 self.havocbot_role_timeout = time + random() * 10 + 10;
922 if (time > self.havocbot_role_timeout)
926 dprint("changing role to offense\n");
927 self.havocbot_role = havocbot_role_kh_offense;
931 dprint("changing role to defense\n");
932 self.havocbot_role = havocbot_role_kh_defense;
934 self.havocbot_role_timeout = 0;
938 if (self.bot_strategytime < time)
940 float key_owner_team;
942 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
943 navigation_goalrating_start();
945 key_owner_team = kh_Key_AllOwnedByWhichTeam();
946 if(key_owner_team == self.team)
947 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
948 else if(key_owner_team == -1)
949 havocbot_goalrating_kh(10000, 40000, 10000); // prefer dropped keys
951 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
953 havocbot_goalrating_items(10000, self.origin, 10000);
954 navigation_goalrating_end();
962 void havocbot_chooserole_kh()
967 self.havocbot_role = havocbot_role_kh_offense;
969 self.havocbot_role = havocbot_role_kh_defense;
971 self.havocbot_role = havocbot_role_kh_freelancer;
974 void havocbot_chooserole()
976 dprint("choose a role...\n");
977 navigation_routetogoal(world);
978 self.bot_strategytime = -1;
980 havocbot_chooserole_ctf();
981 else if (g_domination)
982 havocbot_chooserole_dom();
984 havocbot_chooserole_kh();
986 havocbot_chooserole_race();
987 else // assume anything else is deathmatch
988 havocbot_chooserole_dm();