1 #define HAVOCBOT_CTF_ROLE_NONE 0
2 #define HAVOCBOT_CTF_ROLE_DEFENSE 2
3 #define HAVOCBOT_CTF_ROLE_MIDDLE 4
4 #define HAVOCBOT_CTF_ROLE_OFFENSE 8
5 #define HAVOCBOT_CTF_ROLE_CARRIER 16
6 #define HAVOCBOT_CTF_ROLE_RETRIEVER 32
7 #define HAVOCBOT_CTF_ROLE_ESCORT 64
10 .void() havocbot_previous_role;
12 void() havocbot_role_ctf_middle;
13 void() havocbot_role_ctf_defense;
14 void() havocbot_role_ctf_offense;
15 void() havocbot_role_ctf_carrier;
16 void() havocbot_role_ctf_retriever;
17 void() havocbot_role_ctf_escort;
19 void(entity bot) havocbot_ctf_reset_role;
20 void(float ratingscale, vector org, float sradius) havocbot_goalrating_items;
21 void(float ratingscale, vector org, float sradius) havocbot_goalrating_enemyplayers;
23 .float havocbot_cantfindflag;
24 .float havocbot_role_timeout;
25 .entity ctf_worldflagnext;
28 entity ctf_worldflaglist;
29 vector havocbot_ctf_middlepoint;
30 float havocbot_ctf_middlepoint_radius;
32 entity havocbot_ctf_find_flag(entity bot)
35 f = ctf_worldflaglist;
38 if (bot.team == f.team)
40 f = f.ctf_worldflagnext;
45 entity havocbot_ctf_find_enemy_flag(entity bot)
48 f = ctf_worldflaglist;
51 if (bot.team != f.team)
53 f = f.ctf_worldflagnext;
58 float havocbot_ctf_teamcount(entity bot, vector org, float radius)
68 if(head.team!=bot.team || head.deadflag != DEAD_NO || head == bot)
71 if(vlen(head.origin - org) < radius)
78 void havocbot_goalrating_ctf_ourflag(float ratingscale)
81 head = ctf_worldflaglist;
84 if (self.team == head.team)
86 head = head.ctf_worldflagnext;
89 navigation_routerating(head, ratingscale, 10000);
92 void havocbot_goalrating_ctf_ourbase(float ratingscale)
95 head = ctf_worldflaglist;
98 if (self.team == head.team)
100 head = head.ctf_worldflagnext;
105 navigation_routerating(head.basewaypoint, ratingscale, 10000);
108 void havocbot_goalrating_ctf_enemyflag(float ratingscale)
111 head = ctf_worldflaglist;
114 if (self.team != head.team)
116 head = head.ctf_worldflagnext;
119 navigation_routerating(head, ratingscale, 10000);
122 void havocbot_goalrating_ctf_enemybase(float ratingscale)
124 if not(bot_waypoints_for_items)
126 havocbot_goalrating_ctf_enemyflag(ratingscale);
132 head = havocbot_ctf_find_enemy_flag(self);
137 navigation_routerating(head.basewaypoint, ratingscale, 10000);
140 void havocbot_goalrating_ctf_ourstolenflag(float ratingscale)
144 mf = havocbot_ctf_find_flag(self);
146 if(mf.cnt == FLAG_BASE)
150 navigation_routerating(mf.tag_entity, ratingscale, 10000);
153 void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
156 head = ctf_worldflaglist;
159 // flag is out in the field
160 if(head.cnt != FLAG_BASE)
161 if(head.tag_entity==world) // dropped
165 if(vlen(org-head.origin)<radius)
166 navigation_routerating(head, ratingscale, 10000);
169 navigation_routerating(head, ratingscale, 10000);
172 head = head.ctf_worldflagnext;
176 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
180 head = findchainfloat(bot_pickup, TRUE);
183 // gather health and armor only
185 if (head.health || head.armorvalue)
186 if (vlen(head.origin - org) < sradius)
188 // get the value of the item
189 t = head.bot_pickupevalfunc(self, head) * 0.0001;
191 navigation_routerating(head, t * ratingscale, 500);
197 void havocbot_role_ctf_setrole(entity bot, float role)
199 dprint(strcat(bot.netname," switched to "));
202 case HAVOCBOT_CTF_ROLE_CARRIER:
204 bot.havocbot_role = havocbot_role_ctf_carrier;
205 bot.havocbot_role_timeout = 0;
206 bot.havocbot_cantfindflag = time + 10;
207 bot.bot_strategytime = 0;
209 case HAVOCBOT_CTF_ROLE_DEFENSE:
211 bot.havocbot_role = havocbot_role_ctf_defense;
212 bot.havocbot_role_timeout = 0;
214 case HAVOCBOT_CTF_ROLE_MIDDLE:
216 bot.havocbot_role = havocbot_role_ctf_middle;
217 bot.havocbot_role_timeout = 0;
219 case HAVOCBOT_CTF_ROLE_OFFENSE:
221 bot.havocbot_role = havocbot_role_ctf_offense;
222 bot.havocbot_role_timeout = 0;
224 case HAVOCBOT_CTF_ROLE_RETRIEVER:
226 bot.havocbot_previous_role = bot.havocbot_role;
227 bot.havocbot_role = havocbot_role_ctf_retriever;
228 bot.havocbot_role_timeout = time + 10;
229 bot.bot_strategytime = 0;
231 case HAVOCBOT_CTF_ROLE_ESCORT:
233 bot.havocbot_previous_role = bot.havocbot_role;
234 bot.havocbot_role = havocbot_role_ctf_escort;
235 bot.havocbot_role_timeout = time + 30;
236 bot.bot_strategytime = 0;
242 void havocbot_role_ctf_carrier()
244 if(self.deadflag != DEAD_NO)
246 havocbot_ctf_reset_role(self);
250 if (self.flagcarried == world)
252 havocbot_ctf_reset_role(self);
256 if (self.bot_strategytime < time)
258 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
260 navigation_goalrating_start();
261 havocbot_goalrating_ctf_ourbase(50000);
264 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
266 navigation_goalrating_end();
268 if (self.navigation_hasgoals)
269 self.havocbot_cantfindflag = time + 10;
270 else if (time > self.havocbot_cantfindflag)
272 // Can't navigate to my own base, suicide!
273 // TODO: drop it and wander around
274 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
280 void havocbot_role_ctf_escort()
284 if(self.deadflag != DEAD_NO)
286 havocbot_ctf_reset_role(self);
290 if (self.flagcarried)
292 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
296 // If enemy flag is back on the base switch to previous role
297 ef = havocbot_ctf_find_enemy_flag(self);
298 if(ef.cnt==FLAG_BASE)
300 self.havocbot_role = self.havocbot_previous_role;
301 self.havocbot_role_timeout = 0;
305 // If the flag carrier reached the base switch to defense
306 mf = havocbot_ctf_find_flag(self);
307 if(mf.cnt!=FLAG_BASE)
308 if(vlen(ef.origin - mf.dropped_origin) < 300)
310 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
314 // Set the role timeout if necessary
315 if (!self.havocbot_role_timeout)
317 self.havocbot_role_timeout = time + random() * 30 + 60;
320 // If nothing happened just switch to previous role
321 if (time > self.havocbot_role_timeout)
323 self.havocbot_role = self.havocbot_previous_role;
324 self.havocbot_role_timeout = 0;
328 // Chase the flag carrier
329 if (self.bot_strategytime < time)
331 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
332 navigation_goalrating_start();
333 havocbot_goalrating_ctf_enemyflag(30000);
334 havocbot_goalrating_ctf_ourstolenflag(40000);
335 havocbot_goalrating_items(10000, self.origin, 10000);
336 navigation_goalrating_end();
340 void havocbot_role_ctf_offense()
345 if(self.deadflag != DEAD_NO)
347 havocbot_ctf_reset_role(self);
351 if (self.flagcarried)
353 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
358 mf = havocbot_ctf_find_flag(self);
359 ef = havocbot_ctf_find_enemy_flag(self);
362 if(mf.cnt!=FLAG_BASE)
365 pos = mf.tag_entity.origin;
369 // Try to get it if closer than the enemy base
370 if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
372 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
377 // Escort flag carrier
378 if(ef.cnt!=FLAG_BASE)
381 pos = ef.tag_entity.origin;
385 if(vlen(pos-mf.dropped_origin)>700)
387 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_ESCORT);
392 // About to fail, switch to middlefield
395 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_MIDDLE);
399 // Set the role timeout if necessary
400 if (!self.havocbot_role_timeout)
401 self.havocbot_role_timeout = time + 120;
403 if (time > self.havocbot_role_timeout)
405 havocbot_ctf_reset_role(self);
409 if (self.bot_strategytime < time)
411 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
412 navigation_goalrating_start();
413 havocbot_goalrating_ctf_ourstolenflag(50000);
414 havocbot_goalrating_ctf_enemybase(20000);
415 havocbot_goalrating_items(5000, self.origin, 1000);
416 havocbot_goalrating_items(1000, self.origin, 10000);
417 navigation_goalrating_end();
421 // Retriever (temporary role):
422 void havocbot_role_ctf_retriever()
426 if(self.deadflag != DEAD_NO)
428 havocbot_ctf_reset_role(self);
432 if (self.flagcarried)
434 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
438 // If flag is back on the base switch to previous role
439 mf = havocbot_ctf_find_flag(self);
440 if(mf.cnt==FLAG_BASE)
442 havocbot_ctf_reset_role(self);
446 if (!self.havocbot_role_timeout)
447 self.havocbot_role_timeout = time + 20;
449 if (time > self.havocbot_role_timeout)
451 havocbot_ctf_reset_role(self);
455 if (self.bot_strategytime < time)
460 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
461 navigation_goalrating_start();
462 havocbot_goalrating_ctf_ourstolenflag(50000);
463 havocbot_goalrating_ctf_droppedflags(40000, self.origin, radius);
464 havocbot_goalrating_ctf_enemybase(30000);
465 havocbot_goalrating_items(500, self.origin, radius);
466 navigation_goalrating_end();
470 void havocbot_role_ctf_middle()
474 if(self.deadflag != DEAD_NO)
476 havocbot_ctf_reset_role(self);
480 if (self.flagcarried)
482 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
486 mf = havocbot_ctf_find_flag(self);
487 if(mf.cnt!=FLAG_BASE)
489 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
493 if (!self.havocbot_role_timeout)
494 self.havocbot_role_timeout = time + 10;
496 if (time > self.havocbot_role_timeout)
498 havocbot_ctf_reset_role(self);
502 if (self.bot_strategytime < time)
506 org = havocbot_ctf_middlepoint;
507 org_z = self.origin_z;
509 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
510 navigation_goalrating_start();
511 havocbot_goalrating_ctf_ourstolenflag(50000);
512 havocbot_goalrating_ctf_droppedflags(30000, self.origin, 10000);
513 havocbot_goalrating_enemyplayers(10000, org, havocbot_ctf_middlepoint_radius * 0.5);
514 havocbot_goalrating_items(5000, org, havocbot_ctf_middlepoint_radius * 0.5);
515 havocbot_goalrating_items(2500, self.origin, 10000);
516 havocbot_goalrating_ctf_enemybase(2500);
517 navigation_goalrating_end();
521 void havocbot_role_ctf_defense()
525 if(self.deadflag != DEAD_NO)
527 havocbot_ctf_reset_role(self);
531 if (self.flagcarried)
533 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
537 // If own flag was captured
538 mf = havocbot_ctf_find_flag(self);
539 if(mf.cnt!=FLAG_BASE)
541 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
545 if (!self.havocbot_role_timeout)
546 self.havocbot_role_timeout = time + 30;
548 if (time > self.havocbot_role_timeout)
550 havocbot_ctf_reset_role(self);
553 if (self.bot_strategytime < time)
558 org = mf.dropped_origin;
559 radius = havocbot_ctf_middlepoint_radius;
561 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
562 navigation_goalrating_start();
564 // if enemies are closer to our base, go there
565 local entity head, closestplayer;
566 local float distance, bestdistance;
568 FOR_EACH_PLAYER(head)
570 if(head.deadflag!=DEAD_NO)
573 distance = vlen(org - head.origin);
574 if(distance<bestdistance)
576 closestplayer = head;
577 bestdistance = distance;
582 if(closestplayer.team!=self.team)
583 if(vlen(org - self.origin)>1000)
584 if(checkpvs(self.origin,closestplayer)||random()<0.5)
585 havocbot_goalrating_ctf_ourbase(30000);
587 havocbot_goalrating_ctf_ourstolenflag(20000);
588 havocbot_goalrating_ctf_droppedflags(20000, org, radius);
589 havocbot_goalrating_enemyplayers(15000, org, radius);
590 havocbot_goalrating_items(10000, org, radius);
591 havocbot_goalrating_items(5000, self.origin, 10000);
592 navigation_goalrating_end();
596 void havocbot_calculate_middlepoint()
601 f = ctf_worldflaglist;
609 f = f.ctf_worldflagnext;
611 havocbot_ctf_middlepoint = p1 + ((p2-p1) * 0.5);
612 havocbot_ctf_middlepoint_radius = vlen(p2-p1) * 0.5;
615 void havocbot_ctf_reset_role(entity bot)
617 local float cdefense, cmiddle, coffense;
618 local entity mf, ef, head;
621 if(bot.deadflag != DEAD_NO)
624 if(vlen(havocbot_ctf_middlepoint)==0)
625 havocbot_calculate_middlepoint();
630 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_CARRIER);
634 mf = havocbot_ctf_find_flag(bot);
635 ef = havocbot_ctf_find_enemy_flag(bot);
637 // Retrieve stolen flag
638 if(mf.cnt!=FLAG_BASE)
640 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
644 // If enemy flag is taken go to the middle to intercept pursuers
645 if(ef.cnt!=FLAG_BASE)
647 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
651 // if there is only me on the team switch to offense
653 FOR_EACH_PLAYER(head)
654 if(head.team==bot.team)
659 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
663 // Evaluate best position to take
664 // Count mates on middle position
665 cmiddle = havocbot_ctf_teamcount(bot, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
667 // Count mates on defense position
668 cdefense = havocbot_ctf_teamcount(bot, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
670 // Count mates on offense position
671 coffense = havocbot_ctf_teamcount(bot, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
673 if(cdefense<=coffense)
674 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_DEFENSE);
675 else if(coffense<=cmiddle)
676 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
678 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
681 void havocbot_chooserole_ctf()
683 havocbot_ctf_reset_role(self);