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)
149 navigation_routerating(mf, ratingscale, 10000);
152 void havocbot_goalrating_ctf_droppedflags(float ratingscale, vector org, float radius)
155 head = ctf_worldflaglist;
158 // flag is out in the field
159 if(head.cnt != FLAG_BASE)
160 if(head.tag_entity==world) // dropped
164 if(vlen(org-head.origin)<radius)
165 navigation_routerating(head, ratingscale, 10000);
168 navigation_routerating(head, ratingscale, 10000);
171 head = head.ctf_worldflagnext;
175 void havocbot_goalrating_ctf_carrieritems(float ratingscale, vector org, float sradius)
179 head = findchainfloat(bot_pickup, TRUE);
182 // gather health and armor only
184 if (head.health || head.armorvalue)
185 if (vlen(head.origin - org) < sradius)
187 // get the value of the item
188 t = head.bot_pickupevalfunc(self, head) * 0.0001;
190 navigation_routerating(head, t * ratingscale, 500);
196 void havocbot_role_ctf_setrole(entity bot, float role)
198 dprint(strcat(bot.netname," switched to "));
201 case HAVOCBOT_CTF_ROLE_CARRIER:
203 bot.havocbot_role = havocbot_role_ctf_carrier;
204 bot.havocbot_role_timeout = 0;
205 bot.havocbot_cantfindflag = time + 10;
207 case HAVOCBOT_CTF_ROLE_DEFENSE:
209 bot.havocbot_role = havocbot_role_ctf_defense;
210 bot.havocbot_role_timeout = 0;
212 case HAVOCBOT_CTF_ROLE_MIDDLE:
214 bot.havocbot_role = havocbot_role_ctf_middle;
215 bot.havocbot_role_timeout = 0;
217 case HAVOCBOT_CTF_ROLE_OFFENSE:
219 bot.havocbot_role = havocbot_role_ctf_offense;
220 bot.havocbot_role_timeout = 0;
222 case HAVOCBOT_CTF_ROLE_RETRIEVER:
224 bot.havocbot_previous_role = bot.havocbot_role;
225 bot.havocbot_role = havocbot_role_ctf_retriever;
226 bot.havocbot_role_timeout = time + 10;
228 case HAVOCBOT_CTF_ROLE_ESCORT:
230 bot.havocbot_previous_role = bot.havocbot_role;
231 bot.havocbot_role = havocbot_role_ctf_escort;
232 bot.havocbot_role_timeout = time + 30;
238 void havocbot_role_ctf_carrier()
240 if(self.deadflag != DEAD_NO)
242 havocbot_ctf_reset_role(self);
246 if (self.flagcarried == world)
248 havocbot_ctf_reset_role(self);
252 if (self.bot_strategytime < time)
254 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
256 navigation_goalrating_start();
257 havocbot_goalrating_ctf_ourbase(50000);
260 havocbot_goalrating_ctf_carrieritems(1000, self.origin, 1000);
262 navigation_goalrating_end();
264 if (self.navigation_hasgoals)
265 self.havocbot_cantfindflag = time + 10;
266 else if (time > self.havocbot_cantfindflag)
268 // Can't navigate to my own base, suicide!
269 // TODO: drop it and wander around
270 Damage(self, self, self, 100000, DEATH_KILL, self.origin, '0 0 0');
276 void havocbot_role_ctf_escort()
280 if(self.deadflag != DEAD_NO)
282 havocbot_ctf_reset_role(self);
286 if (self.flagcarried)
288 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
292 // If enemy flag is back on the base switch to previous role
293 ef = havocbot_ctf_find_enemy_flag(self);
294 if(ef.cnt==FLAG_BASE)
296 self.havocbot_role = self.havocbot_previous_role;
297 self.havocbot_role_timeout = 0;
301 // If the flag carrier reached the base switch to defense
302 mf = havocbot_ctf_find_flag(self);
303 if(mf.cnt!=FLAG_BASE)
304 if(vlen(ef.origin - mf.dropped_origin) < 300)
306 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_DEFENSE);
310 // Set the role timeout if necessary
311 if (!self.havocbot_role_timeout)
313 self.havocbot_role_timeout = time + random() * 30 + 60;
316 // If nothing happened just switch to previous role
317 if (time > self.havocbot_role_timeout)
319 self.havocbot_role = self.havocbot_previous_role;
320 self.havocbot_role_timeout = 0;
324 // Chase the flag carrier
325 if (self.bot_strategytime < time)
327 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
328 navigation_goalrating_start();
329 havocbot_goalrating_ctf_enemyflag(30000);
330 havocbot_goalrating_ctf_ourstolenflag(40000);
331 havocbot_goalrating_items(10000, self.origin, 10000);
332 navigation_goalrating_end();
336 void havocbot_role_ctf_offense()
341 if(self.deadflag != DEAD_NO)
343 havocbot_ctf_reset_role(self);
347 if (self.flagcarried)
349 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
354 mf = havocbot_ctf_find_flag(self);
355 ef = havocbot_ctf_find_enemy_flag(self);
358 if(mf.cnt!=FLAG_BASE)
361 pos = mf.tag_entity.origin;
365 // Try to get it if closer than the enemy base
366 if(vlen(self.origin-ef.dropped_origin)>vlen(self.origin-pos))
368 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
373 // Escort flag carrier
374 if(ef.cnt!=FLAG_BASE)
377 pos = ef.tag_entity.origin;
381 if(vlen(pos-mf.dropped_origin)>700)
383 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_ESCORT);
388 // About to fail, switch to middlefield
391 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_MIDDLE);
395 // Set the role timeout if necessary
396 if (!self.havocbot_role_timeout)
397 self.havocbot_role_timeout = time + 120;
399 if (time > self.havocbot_role_timeout)
401 havocbot_ctf_reset_role(self);
405 if (self.bot_strategytime < time)
407 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
408 navigation_goalrating_start();
409 havocbot_goalrating_ctf_ourstolenflag(50000);
410 havocbot_goalrating_ctf_enemybase(20000);
411 havocbot_goalrating_items(5000, self.origin, 1000);
412 havocbot_goalrating_items(1000, self.origin, 10000);
413 navigation_goalrating_end();
417 // Retriever (temporary role):
418 void havocbot_role_ctf_retriever()
422 if(self.deadflag != DEAD_NO)
424 havocbot_ctf_reset_role(self);
428 if (self.flagcarried)
430 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
434 // If flag is back on the base switch to previous role
435 mf = havocbot_ctf_find_flag(self);
436 if(mf.cnt==FLAG_BASE)
438 havocbot_ctf_reset_role(self);
442 if (!self.havocbot_role_timeout)
443 self.havocbot_role_timeout = time + 20;
445 if (time > self.havocbot_role_timeout)
447 havocbot_ctf_reset_role(self);
451 if (self.bot_strategytime < time)
456 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
457 navigation_goalrating_start();
458 havocbot_goalrating_ctf_ourstolenflag(50000);
459 havocbot_goalrating_ctf_droppedflags(40000, self.origin, radius);
460 havocbot_goalrating_ctf_enemybase(30000);
461 havocbot_goalrating_items(500, self.origin, radius);
462 navigation_goalrating_end();
466 void havocbot_role_ctf_middle()
470 if(self.deadflag != DEAD_NO)
472 havocbot_ctf_reset_role(self);
476 if (self.flagcarried)
478 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
482 mf = havocbot_ctf_find_flag(self);
483 if(mf.cnt!=FLAG_BASE)
485 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
489 if (!self.havocbot_role_timeout)
490 self.havocbot_role_timeout = time + 10;
492 if (time > self.havocbot_role_timeout)
494 havocbot_ctf_reset_role(self);
498 if (self.bot_strategytime < time)
502 org = havocbot_ctf_middlepoint;
503 org_z = self.origin_z;
505 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
506 navigation_goalrating_start();
507 havocbot_goalrating_ctf_ourstolenflag(50000);
508 havocbot_goalrating_ctf_droppedflags(30000, self.origin, 10000);
509 havocbot_goalrating_enemyplayers(10000, org, havocbot_ctf_middlepoint_radius * 0.5);
510 havocbot_goalrating_items(5000, org, havocbot_ctf_middlepoint_radius * 0.5);
511 havocbot_goalrating_items(2500, self.origin, 10000);
512 havocbot_goalrating_ctf_enemybase(2500);
513 navigation_goalrating_end();
517 void havocbot_role_ctf_defense()
521 if(self.deadflag != DEAD_NO)
523 havocbot_ctf_reset_role(self);
527 if (self.flagcarried)
529 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_CARRIER);
533 // If own flag was captured
534 mf = havocbot_ctf_find_flag(self);
535 if(mf.cnt!=FLAG_BASE)
537 havocbot_role_ctf_setrole(self, HAVOCBOT_CTF_ROLE_RETRIEVER);
541 if (!self.havocbot_role_timeout)
542 self.havocbot_role_timeout = time + 30;
544 if (time > self.havocbot_role_timeout)
546 havocbot_ctf_reset_role(self);
549 if (self.bot_strategytime < time)
554 org = mf.dropped_origin;
555 radius = havocbot_ctf_middlepoint_radius;
557 self.bot_strategytime = time + cvar("bot_ai_strategyinterval");
558 navigation_goalrating_start();
560 // if enemies are closer to our base, go there
561 local entity head, closestplayer;
562 local float distance, bestdistance;
564 FOR_EACH_PLAYER(head)
566 if(head.deadflag!=DEAD_NO)
569 distance = vlen(org - head.origin);
570 if(distance<bestdistance)
572 closestplayer = head;
573 bestdistance = distance;
578 if(closestplayer.team!=self.team)
579 if(vlen(org - self.origin)>1000)
580 if(checkpvs(self.origin,closestplayer)||random()<0.5)
581 havocbot_goalrating_ctf_ourbase(30000);
583 havocbot_goalrating_ctf_ourstolenflag(20000);
584 havocbot_goalrating_ctf_droppedflags(20000, org, radius);
585 havocbot_goalrating_enemyplayers(15000, org, radius);
586 havocbot_goalrating_items(10000, org, radius);
587 havocbot_goalrating_items(5000, self.origin, 10000);
588 navigation_goalrating_end();
592 void havocbot_calculate_middlepoint()
597 f = ctf_worldflaglist;
605 f = f.ctf_worldflagnext;
607 havocbot_ctf_middlepoint = p1 + ((p2-p1) * 0.5);
608 havocbot_ctf_middlepoint_radius = vlen(p2-p1) * 0.5;
611 void havocbot_ctf_reset_role(entity bot)
613 local float cdefense, cmiddle, coffense;
614 local entity mf, ef, head;
617 if(bot.deadflag != DEAD_NO)
620 if(vlen(havocbot_ctf_middlepoint)==0)
621 havocbot_calculate_middlepoint();
626 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_CARRIER);
630 mf = havocbot_ctf_find_flag(bot);
631 ef = havocbot_ctf_find_enemy_flag(bot);
633 // Retrieve stolen flag
634 if(mf.cnt!=FLAG_BASE)
636 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_RETRIEVER);
640 // If enemy flag is taken go to the middle to intercept pursuers
641 if(ef.cnt!=FLAG_BASE)
643 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
647 // if there is only me on the team switch to offense
649 FOR_EACH_PLAYER(head)
650 if(head.team==bot.team)
655 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
659 // Evaluate best position to take
660 // Count mates on middle position
661 cmiddle = havocbot_ctf_teamcount(bot, havocbot_ctf_middlepoint, havocbot_ctf_middlepoint_radius * 0.5);
663 // Count mates on defense position
664 cdefense = havocbot_ctf_teamcount(bot, mf.dropped_origin, havocbot_ctf_middlepoint_radius * 0.5);
666 // Count mates on offense position
667 coffense = havocbot_ctf_teamcount(bot, ef.dropped_origin, havocbot_ctf_middlepoint_radius);
669 if(cdefense<=coffense)
670 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_DEFENSE);
671 else if(coffense<=cmiddle)
672 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_OFFENSE);
674 havocbot_role_ctf_setrole(bot, HAVOCBOT_CTF_ROLE_MIDDLE);
677 void havocbot_chooserole_ctf()
679 havocbot_ctf_reset_role(self);