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 || head == self.ignoregoal )
111 // Check if the item can be picked up safely
112 if(head.classname == "droppedweapon")
114 traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
116 d = pointcontents(trace_endpos + '0 0 1');
117 if(d & CONTENT_WATER || d & CONTENT_SLIME || d & CONTENT_LAVA)
122 if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
133 FOR_EACH_PLAYER(player)
136 if ( self == player || player.deadflag )
139 d = vlen(player.origin - head.origin); // distance between player and item
141 if ( player.team == self.team )
143 if ( clienttype(player) != CLIENTTYPE_REAL || discard )
146 if( d > friend_distance)
153 if( head.health && player.health > self.health )
156 if( head.armorvalue && player.armorvalue > self.armorvalue)
160 if( (player.weapons & head.weapons) != head.weapons)
163 if (head.ammo_shells && player.ammo_shells > self.ammo_shells)
166 if (head.ammo_nails && player.ammo_nails > self.ammo_nails)
169 if (head.ammo_rockets && player.ammo_rockets > self.ammo_rockets)
172 if (head.ammo_cells && player.ammo_cells > self.ammo_cells )
179 // If enemy only track distances
180 // TODO: track only if visible ?
181 if( d < enemy_distance )
186 // Rate the item only if no one needs it, or if an enemy is closer to it
187 if ( (enemy_distance < friend_distance && distance < enemy_distance) ||
188 (friend_distance > cvar("bot_ai_friends_aware_pickup_radius") ) || !discard )
190 // rating = head.bot_pickupevalfunc(self, head);
191 rating = havocbot_pickupevalfunc(head);
196 // rating = head.bot_pickupevalfunc(self, head);
197 rating = havocbot_pickupevalfunc(head);
201 navigation_routerating(head, rating * ratingscale, 2000);
207 void havocbot_goalrating_controlpoints(float ratingscale, vector org, float sradius)
210 head = findchain(classname, "dom_controlpoint");
213 if (vlen(head.origin - org) < sradius)
215 if(head.cnt > -1) // this is just being fought for
216 navigation_routerating(head, ratingscale, 5000);
217 else if(head.goalentity.cnt == 0) // unclaimed point
218 navigation_routerating(head, ratingscale * 0.5, 5000);
219 else if(head.goalentity.team != self.team) // other team's point
220 navigation_routerating(head, ratingscale * 0.2, 5000);
227 // LordHavoc: this function was already unused, but for waypoints to be a
228 // useful goal the bots would have to seek out the least-recently-visited
229 // ones, not the closest
230 void havocbot_goalrating_waypoints(float ratingscale, vector org, float sradius)
233 head = findchain(classname, "waypoint");
236 if (vlen(head.origin - org) < sradius && vlen(head.origin - org) > 100)
237 navigation_routerating(head, ratingscale, 2000);
243 void havocbot_goalrating_enemyplayers(float ratingscale, vector org, float sradius)
246 local float t, noteam;
247 noteam = ((self.team == 0) || (teamplay == 0)); // fteqcc sucks
249 FOR_EACH_PLAYER(head)
253 if ((noteam && (!bot_ignore_bots || clienttype(head) == CLIENTTYPE_REAL)) || head.team != self.team)
255 if (vlen(head.origin - org) > sradius)
258 // rate only visible enemies
260 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
261 if (trace_fraction < 1 || trace_ent != head)
265 if(head.flags & FL_INWATER || head.flags & FL_PARTIALGROUND)
269 if(head.flags & FL_ONGROUND == 0)
271 traceline(head.origin, head.origin + '0 0 -1500', TRUE, world);
272 t = pointcontents(trace_endpos + '0 0 1');
273 if( t != CONTENT_SOLID )
274 if(t & CONTENT_WATER || t & CONTENT_SLIME || t & CONTENT_LAVA)
276 if(tracebox_hits_trigger_hurt(head.origin, head.mins, head.maxs, trace_endpos))
280 t = (self.health + self.armorvalue ) / (head.health + head.armorvalue );
281 navigation_routerating(head, t * ratingscale, 2000);
287 void() havocbot_role_ctf_middle;
288 void() havocbot_role_ctf_defense;
289 void() havocbot_role_ctf_offense;
290 void() havocbot_role_ctf_interceptor;
292 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
296 head = findchainfloat(bot_pickup, TRUE);
299 // look for health and armor only
300 if (head.solid) // must be possible to pick up (respawning items don't count)
301 if (head.health || head.armorvalue)
302 if (vlen(head.origin - org) < sradius)
305 //if (!head.bot_pickupevalfunc || head.model == "")
307 // get the value of the item
308 t = head.bot_pickupevalfunc(self, head) * 0.0001;
310 navigation_routerating(head, t * ratingscale, 500);
316 entity ctf_worldflaglist;
317 .entity ctf_worldflagnext;
318 void havocbot_goalrating_ctf_ourflag(float ratingscale)
321 head = ctf_worldflaglist;
324 if (self.team == head.team)
326 head = head.ctf_worldflagnext;
329 navigation_routerating(head, ratingscale, 10000);
332 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
335 head = ctf_worldflaglist;
338 if (self.team != head.team)
340 head = head.ctf_worldflagnext;
343 navigation_routerating(head, ratingscale, 10000);
346 void havocbot_goalrating_ctf_enemybase(float ratingscale)
348 // div0: needs a change in the CTF code
351 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
354 head = ctf_worldflaglist;
357 if (self.team == head.team)
359 head = head.ctf_worldflagnext;
362 if (head.cnt != FLAG_BASE)
363 navigation_routerating(head, ratingscale, 10000);
366 void havocbot_goalrating_ctf_droppedflags(float ratingscale)
369 head = ctf_worldflaglist;
372 if (head.cnt != FLAG_BASE) // flag is carried or out in the field
373 navigation_routerating(head, ratingscale, 10000);
374 head = head.ctf_worldflagnext;
378 // CTF: (always teamplay)
380 //role rogue: (is this used?)
381 //pick up items and dropped flags (with big rating boost to dropped flags)
382 void havocbot_role_ctf_rogue()
384 if (self.bot_strategytime < time)
386 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
387 navigation_goalrating_start();
388 havocbot_goalrating_ctf_droppedflags(5000);
389 //havocbot_goalrating_enemyplayers(3000, self.origin, 3000);
390 havocbot_goalrating_items(10000, self.origin, 10000);
391 navigation_goalrating_end();
396 //pick up armor and health
397 //go to our flag spot
398 .float bot_cantfindflag;
399 void havocbot_role_ctf_carrier()
401 if (self.flagcarried == world)
403 dprint("changing role to middle\n");
404 self.havocbot_role = havocbot_role_ctf_middle;
405 self.havocbot_role_timeout = 0;
408 if (self.bot_strategytime < time)
410 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
411 navigation_goalrating_start();
412 havocbot_goalrating_ctf_ourflag(50000);
413 if (navigation_bestgoal)
414 self.bot_cantfindflag = time + 10;
415 else if (time > self.bot_cantfindflag)
417 // can't navigate to our own flag :(
418 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
420 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
421 navigation_goalrating_end();
426 //pick up armor and health
427 //if rockets < 25 || health < 100, change role to middle
428 //if carrying flag, change role to flag carrier
429 //if our flag taken, change role to interceptor
430 //(60-90 second timer) change role to middle
432 void havocbot_role_ctf_offense()
435 if (self.flagcarried)
437 dprint("changing role to carrier\n");
438 self.havocbot_role = havocbot_role_ctf_carrier;
439 self.havocbot_role_timeout = 0;
440 self.bot_cantfindflag = time + 10;
444 f = ctf_worldflaglist;
447 if (self.team == f.team)
449 f = f.ctf_worldflagnext;
451 if (f.cnt != FLAG_BASE && canreach(f))
453 dprint("changing role to interceptor\n");
454 self.havocbot_previous_role = self.havocbot_role;
455 self.havocbot_role = havocbot_role_ctf_interceptor;
456 self.havocbot_role_timeout = 0;
459 if (!self.havocbot_role_timeout)
460 self.havocbot_role_timeout = time + random() * 30 + 60;
461 if (time > self.havocbot_role_timeout)
463 dprint("changing role to middle\n");
464 self.havocbot_role = havocbot_role_ctf_middle;
465 self.havocbot_role_timeout = 0;
468 if (self.bot_strategytime < time)
470 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
471 navigation_goalrating_start();
472 havocbot_goalrating_ctf_ourstolenflag(50000);
473 havocbot_goalrating_ctf_enemyflag(30000);
474 havocbot_goalrating_ctf_enemybase(20000);
475 havocbot_goalrating_items(10000, self.origin, 10000);
476 navigation_goalrating_end();
480 //role interceptor (temporary role):
482 //if carrying flag, change role to flag carrier
483 //if our flag is back, change role to previous role
485 //go to least recently visited area
486 void havocbot_role_ctf_interceptor()
489 if (self.flagcarried)
491 dprint("changing role to carrier\n");
492 self.havocbot_role = havocbot_role_ctf_carrier;
493 self.havocbot_role_timeout = 0;
494 self.bot_cantfindflag = time + 10;
498 f = ctf_worldflaglist;
501 if (self.team == f.team)
503 f = f.ctf_worldflagnext;
505 if (f.cnt == FLAG_BASE)
507 dprint("changing role back\n");
508 self.havocbot_role = self.havocbot_previous_role;
509 self.havocbot_role_timeout = 0;
513 if (self.bot_strategytime < time)
515 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
516 navigation_goalrating_start();
517 havocbot_goalrating_ctf_ourstolenflag(50000);
518 havocbot_goalrating_ctf_droppedflags(50000);
519 havocbot_goalrating_items(10000, self.origin, 10000);
520 navigation_goalrating_end();
526 //if carrying flag, change role to flag carrier
527 //if our flag taken, change role to interceptor
528 //if see flag (of either team) follow it (this has many implications)
529 //(10-20 second timer) change role to defense or offense
530 //go to least recently visited area
531 void havocbot_role_ctf_middle()
534 if (self.flagcarried)
536 dprint("changing role to carrier\n");
537 self.havocbot_role = havocbot_role_ctf_carrier;
538 self.havocbot_role_timeout = 0;
539 self.bot_cantfindflag = time + 10;
543 f = ctf_worldflaglist;
546 if (self.team == f.team)
548 f = f.ctf_worldflagnext;
550 if (f.cnt != FLAG_BASE && canreach(f))
552 dprint("changing role to interceptor\n");
553 self.havocbot_previous_role = self.havocbot_role;
554 self.havocbot_role = havocbot_role_ctf_interceptor;
555 self.havocbot_role_timeout = 0;
558 if (!self.havocbot_role_timeout)
559 self.havocbot_role_timeout = time + random() * 10 + 10;
560 if (time > self.havocbot_role_timeout)
564 dprint("changing role to offense\n");
565 self.havocbot_role = havocbot_role_ctf_offense;
569 dprint("changing role to defense\n");
570 self.havocbot_role = havocbot_role_ctf_defense;
572 self.havocbot_role_timeout = 0;
576 if (self.bot_strategytime < time)
578 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
579 navigation_goalrating_start();
580 havocbot_goalrating_ctf_ourstolenflag(50000);
581 havocbot_goalrating_ctf_droppedflags(30000);
582 //havocbot_goalrating_enemyplayers(1000, self.origin, 1000);
583 havocbot_goalrating_items(10000, self.origin, 10000);
584 navigation_goalrating_end();
589 //if rockets < 25 || health < 100, change role to middle
590 //if carrying flag, change role to flag carrier
591 //if our flag taken, change role to interceptor
592 //(30-50 second timer) change role to middle
593 //move to nearest unclaimed defense spot
594 void havocbot_role_ctf_defense()
597 if (self.flagcarried)
599 dprint("changing role to carrier\n");
600 self.havocbot_role = havocbot_role_ctf_carrier;
601 self.havocbot_role_timeout = 0;
602 self.bot_cantfindflag = time + 10;
606 f = ctf_worldflaglist;
609 if (self.team == f.team)
611 f = f.ctf_worldflagnext;
613 if (f.cnt != FLAG_BASE && canreach(f))
615 dprint("changing role to interceptor\n");
616 self.havocbot_previous_role = self.havocbot_role;
617 self.havocbot_role = havocbot_role_ctf_interceptor;
618 self.havocbot_role_timeout = 0;
621 if (!self.havocbot_role_timeout)
622 self.havocbot_role_timeout = time + random() * 20 + 30;
623 if (time > self.havocbot_role_timeout)
625 dprint("changing role to middle\n");
626 self.havocbot_role = havocbot_role_ctf_middle;
627 self.havocbot_role_timeout = 0;
630 if (self.bot_strategytime < time)
632 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
633 navigation_goalrating_start();
634 havocbot_goalrating_ctf_ourstolenflag(200000);
635 havocbot_goalrating_ctf_droppedflags(50000);
636 havocbot_goalrating_items(10000, f.origin, 10000);
637 navigation_goalrating_end();
640 // FIXME: place info_ctf_defensepoint entities in CTF maps and use them
641 // change position occasionally
642 if (time > self.bot_strategytime || self.goalentity.classname != "info_ctf_defensepoint")
644 self.bot_strategytime = time + random() * 45 + 15;
645 self.goalentity = world;
646 head = findchain(classname, "info_ctf_defensepoint");
649 if (time > head.count)
651 self.goalentity = head;
656 // if there are no defensepoints defined, switch to middle
657 if (self.goalentity == world)
659 dprint("changing role to middle\n");
660 self.havocbot_role = havocbot_role_ctf_middle;
661 self.havocbot_role_timeout = 0;
665 // keep anyone else from taking this spot
666 if (self.goalentity != world)
667 self.goalentity.count = time + 0.5;
672 // choose a role according to the situation
673 void() havocbot_role_dm;
674 void havocbot_chooserole_ctf()
677 dprint("choose CTF role...\n");
678 if (self.team == COLOR_TEAM3 || self.team == COLOR_TEAM4)
679 self.havocbot_role = havocbot_role_ctf_rogue;
684 self.havocbot_role = havocbot_role_ctf_offense;
686 self.havocbot_role = havocbot_role_ctf_middle;
688 self.havocbot_role = havocbot_role_ctf_defense;
693 //go to best items, or control points you don't own
694 void havocbot_role_dom()
696 if (self.bot_strategytime < time)
698 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
699 navigation_goalrating_start();
700 havocbot_goalrating_controlpoints(10000, self.origin, 15000);
701 havocbot_goalrating_items(8000, self.origin, 8000);
702 //havocbot_goalrating_enemyplayers(3000, self.origin, 2000);
703 //havocbot_goalrating_waypoints(1, self.origin, 1000);
704 navigation_goalrating_end();
710 void havocbot_role_dm()
712 if (self.bot_strategytime < time)
714 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
715 navigation_goalrating_start();
716 havocbot_goalrating_items(10000, self.origin, 10000);
717 havocbot_goalrating_enemyplayers(5000, self.origin, 20000);
718 //havocbot_goalrating_waypoints(1, self.origin, 1000);
719 navigation_goalrating_end();
724 //go to next checkpoint, and annoy enemies
725 .float race_checkpoint;
726 void havocbot_role_race()
729 if (self.bot_strategytime < time)
731 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
732 navigation_goalrating_start();
734 havocbot_goalrating_items(100, self.origin, 10000);
735 havocbot_goalrating_enemyplayers(500, self.origin, 20000);
738 for(e = world; (e = find(e, classname, "trigger_race_checkpoint")) != world; )
740 if(e.cnt == self.race_checkpoint)
742 navigation_routerating(e, 1000000, 5000);
744 else if(self.race_checkpoint == -1)
746 navigation_routerating(e, 1000000, 5000);
750 navigation_goalrating_end();
754 void havocbot_chooserole_dm()
756 self.havocbot_role = havocbot_role_dm;
759 void havocbot_chooserole_race()
761 self.havocbot_role = havocbot_role_race;
764 void havocbot_chooserole_dom()
766 self.havocbot_role = havocbot_role_dom;
774 entity kh_worldkeylist;
775 .entity kh_worldkeynext;
776 void havocbot_goalrating_kh(float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
779 for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
781 if(head.owner == self)
783 if(!kh_tracking_enabled)
785 // if it's carried by our team we know about it
786 // otherwise we have to see it to know about it
787 if(!head.owner || head.team != self.team)
789 traceline(self.origin + self.view_ofs, head.origin, MOVE_NOMONSTERS, self);
790 if (trace_fraction < 1 && trace_ent != head)
791 continue; // skip what I can't see
795 navigation_routerating(head, ratingscale_dropped, 100000);
796 else if(head.team == self.team)
797 navigation_routerating(head, ratingscale_team, 100000);
799 navigation_routerating(head, ratingscale_enemy, 100000);
803 void() havocbot_role_kh_carrier;
804 void() havocbot_role_kh_defense;
805 void() havocbot_role_kh_offense;
806 void() havocbot_role_kh_freelancer;
807 void havocbot_role_kh_carrier()
809 if (!(self.items & IT_KEY1))
811 dprint("changing role to freelancer\n");
812 self.havocbot_role = havocbot_role_kh_freelancer;
813 self.havocbot_role_timeout = 0;
817 if (self.bot_strategytime < time)
819 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
820 navigation_goalrating_start();
822 if(kh_Key_AllOwnedByWhichTeam() == self.team)
823 havocbot_goalrating_kh(100000, 1, 1); // bring home
825 havocbot_goalrating_kh(40000, 40000, 1000); // play defensively
827 havocbot_goalrating_items(10000, self.origin, 10000);
828 navigation_goalrating_end();
832 void havocbot_role_kh_defense()
834 if (self.items & IT_KEY1)
836 dprint("changing role to carrier\n");
837 self.havocbot_role = havocbot_role_kh_carrier;
838 self.havocbot_role_timeout = 0;
842 if (!self.havocbot_role_timeout)
843 self.havocbot_role_timeout = time + random() * 10 + 20;
844 if (time > self.havocbot_role_timeout)
846 dprint("changing role to freelancer\n");
847 self.havocbot_role = havocbot_role_kh_freelancer;
848 self.havocbot_role_timeout = 0;
852 if (self.bot_strategytime < time)
854 float key_owner_team;
855 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
856 navigation_goalrating_start();
858 key_owner_team = kh_Key_AllOwnedByWhichTeam();
859 if(key_owner_team == self.team)
860 havocbot_goalrating_kh(100000, 1, 1); // defend key carriers
861 else if(key_owner_team == -1)
862 havocbot_goalrating_kh(40000, 10000, 1); // play defensively
864 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
866 havocbot_goalrating_items(10000, self.origin, 10000);
867 navigation_goalrating_end();
871 void havocbot_role_kh_offense()
873 if (self.items & IT_KEY1)
875 dprint("changing role to carrier\n");
876 self.havocbot_role = havocbot_role_kh_carrier;
877 self.havocbot_role_timeout = 0;
881 if (!self.havocbot_role_timeout)
882 self.havocbot_role_timeout = time + random() * 10 + 20;
883 if (time > self.havocbot_role_timeout)
885 dprint("changing role to freelancer\n");
886 self.havocbot_role = havocbot_role_kh_freelancer;
887 self.havocbot_role_timeout = 0;
891 if (self.bot_strategytime < time)
893 float key_owner_team;
895 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
896 navigation_goalrating_start();
898 key_owner_team = kh_Key_AllOwnedByWhichTeam();
899 if(key_owner_team == self.team)
900 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
901 else if(key_owner_team == -1)
902 havocbot_goalrating_kh(1, 10000, 40000); // play offensively
904 havocbot_goalrating_kh(1, 1, 100000); // ATTACK! EMERGENCY!
906 havocbot_goalrating_items(10000, self.origin, 10000);
907 navigation_goalrating_end();
911 void havocbot_role_kh_freelancer()
913 if (self.items & IT_KEY1)
915 dprint("changing role to carrier\n");
916 self.havocbot_role = havocbot_role_kh_carrier;
917 self.havocbot_role_timeout = 0;
921 if (!self.havocbot_role_timeout)
922 self.havocbot_role_timeout = time + random() * 10 + 10;
923 if (time > self.havocbot_role_timeout)
927 dprint("changing role to offense\n");
928 self.havocbot_role = havocbot_role_kh_offense;
932 dprint("changing role to defense\n");
933 self.havocbot_role = havocbot_role_kh_defense;
935 self.havocbot_role_timeout = 0;
939 if (self.bot_strategytime < time)
941 float key_owner_team;
943 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
944 navigation_goalrating_start();
946 key_owner_team = kh_Key_AllOwnedByWhichTeam();
947 if(key_owner_team == self.team)
948 havocbot_goalrating_kh(100000, 1, 1); // defend anyway
949 else if(key_owner_team == -1)
950 havocbot_goalrating_kh(10000, 40000, 10000); // prefer dropped keys
952 havocbot_goalrating_kh(1, 1, 100000); // ATTACK ANYWAY
954 havocbot_goalrating_items(10000, self.origin, 10000);
955 navigation_goalrating_end();
963 void havocbot_chooserole_kh()
968 self.havocbot_role = havocbot_role_kh_offense;
970 self.havocbot_role = havocbot_role_kh_defense;
972 self.havocbot_role = havocbot_role_kh_freelancer;
975 void havocbot_chooserole()
977 dprint("choose a role...\n");
978 navigation_routetogoal(world);
979 self.bot_strategytime = -1;
981 havocbot_chooserole_ctf();
982 else if (g_domination)
983 havocbot_chooserole_dom();
985 havocbot_chooserole_kh();
987 havocbot_chooserole_race();
988 else // assume anything else is deathmatch
989 havocbot_chooserole_dm();